diff --git a/.gitignore b/.gitignore index 3425b85ff..6b65bb21d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .idea/* target/* -*.iml \ No newline at end of file +*.iml +.java-version \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 9bcf99945..8ea4e5783 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,4 @@ language: java jdk: - oraclejdk8 + - oraclejdk11 diff --git a/CHANGELOG.md b/CHANGELOG.md index ee919be2e..cc0afb897 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,52 @@ 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***: `IO` is now sealed and moved to its own package. Most previous constructions using the static + factory methods should continue to work (by simply targeting `Supplier` now instead of an + anonymous `IO`), but some might need to be reworked, and subtyping is obviously no longer + supported. +- ***Breaking Change***: Breaking all dependency on `java.util.function` types across the board. All `Fn*` types target + methods now support throwing `Throwable`; `apply` is now defaulted and will simply bypass javac + to throw checked exceptions as if they were unchecked. All `Checked` variants have been + eliminated as a consequence, as they are no longer necessary. Also, straggler functions like + `Partial2/3` that only existed to aid in partial application of non-curried functions are now + superfluous, and have also been eliminated. +- ***Breaking Change***: `FoldRight` now requires `Lazy` as part of its interface to support short-circuiting operations +- ***Breaking Change***: Eliminated all raw types and java11 warnings. This required using capture in unification + parameters for Functor and friends, so nearly every functor's type-signature changed. +- ***Breaking Change***: `Strong` is now called `Cartesian` to better reflect the type of strength +- ***Breaking Change***: new Optic type hierarchy more faithfully encodes profunctor constraints on optics, new `Optic` + type is now the supertype of `Lens` and `Iso`, and `lens` package has been moved to `optics` +- ***Breaking Change***: `Try` and `Either` no longer preserve `Throwable` type since it was inherently not type-safe + anyway; Try is therefore no longer a `Bifunctor`, and `orThrow` can be used to declare checked + exceptions that could be caught by corresponding catch blocks +- `IO` is now stack-safe, regardless of whether the composition nests linearly or recursively + +### Added +- `Lazy`, a monad supporting stack-safe lazy evaluation +- `LazyRec`, a function for writing stack-safe recursive algorithms embedded in `Lazy` +- `Applicative#lazyZip`, for zipping two applicatives in a way that might not require evaluation of one applicative +- `MonadT`, a general interface representing monad transformers +- `MaybeT`, a monad transformer for `Maybe` +- `EitherT`, a monad transformer for `Either` +- `IdentityT`, a monad transformer for `Identity` +- `LazyT`, a monad transformer for `Lazy` +- `Endo`, a monoid formed by `Fn1` under composition +- `State`, the state `Monad` +- `Downcast`, a function supporting unchecked down-casting +- `Cocartesian`, profunctorial strength in cocartesian coproduct terms +- `Prism`, an `Optic` that is nearly an `Iso` but can fail in one direction +- `Market`, `Tagged`, profunctors supporting optics +- `Re` for viewing an `Optic` in one direction reliably +- `Pre` for viewing at most one value from an `Optic` in one direction +- `SideEffect`, for representing side-effects runnable by `IO` +- `IO#safe`, mapping an `IO` to an `IO>` that will never throw +- `IO#ensuring`, like `finally` semantics for `IO`s +- `IO#throwing`, for producing an `IO` that will throw a given `Throwable` when executed +- `Bracket`, for bracketing an `IO` operation with a mapping operation and a cleanup operation + +## [3.3.0] - 2019-02-18 ### Added - `MergeMaps`, a `Monoid` on `Map` formed by `Map#merge` - `CheckedEffect` is now a `CheckedFn1` @@ -16,7 +62,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - test jar is now published - `Monad#join` static alias for `flatMap(id())` - `Effect#effect` static factory method taking `Fn1` +- `IO#unsafePerformAsyncIO` overloads for running `IO`s asynchronously - `IO`s automatically encode parallelism in composition +- `IO#exceptionally` for recovering from failure during `IO` operation +- `Optic`, a generic supertype for all profunctor optics ### Fixed - issue where certain ways to compose `Effect`s unintentionally nullified the effect @@ -426,7 +475,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `Monadic/Dyadic/TriadicFunction`, `Predicate`, `Tuple2`, `Tuple3` - `Functor`, `BiFunctor`, `ProFunctor` -[Unreleased]: https://github.com/palatable/lambda/compare/lambda-3.2.0...HEAD +[Unreleased]: https://github.com/palatable/lambda/compare/lambda-3.3.0...HEAD +[3.3.0]: https://github.com/palatable/lambda/compare/lambda-3.2.0...3.3.0 [3.2.0]: https://github.com/palatable/lambda/compare/lambda-3.1.0...lambda-3.2.0 [3.1.0]: https://github.com/palatable/lambda/compare/lambda-3.0.3...lambda-3.1.0 [3.0.3]: https://github.com/palatable/lambda/compare/lambda-3.0.2...lambda-3.0.3 diff --git a/README.md b/README.md index 65501c222..476f89ebc 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ ====== [![Build Status](https://img.shields.io/travis/palatable/lambda/master.svg)](https://travis-ci.org/palatable/lambda) [![Lambda](https://img.shields.io/maven-central/v/com.jnape.palatable/lambda.svg)](http://search.maven.org/#search%7Cga%7C1%7Ccom.jnape.palatable.lambda) +[![Join the chat at https://gitter.im/palatable/lambda](https://badges.gitter.im/palatable/lambda.svg)](https://gitter.im/palatable/lambda?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) Functional patterns for Java @@ -57,14 +58,14 @@ Add the following dependency to your: com.jnape.palatable lambda - 3.2.0 + 3.3.0 ``` `build.gradle` ([Gradle](https://docs.gradle.org/current/userguide/dependency_management.html)): ```gradle -compile group: 'com.jnape.palatable', name: 'lambda', version: '3.2.0' +compile group: 'com.jnape.palatable', name: 'lambda', version: '3.3.0' ``` Examples diff --git a/pom.xml b/pom.xml index 145522c52..ddf6ce35a 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ lambda - 3.3.0 + 4.0.0 jar Lambda @@ -53,7 +53,6 @@ - 3.1 1.2 3.3 1.3 @@ -81,12 +80,6 @@ ${traitor.version} test - - org.apache.commons - commons-lang3 - ${commons-lang3.version} - test - diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Either.java b/src/main/java/com/jnape/palatable/lambda/adt/Either.java index 00f3bf787..29e421570 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Either.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Either.java @@ -2,24 +2,24 @@ import com.jnape.palatable.lambda.adt.choice.Choice3; import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; +import com.jnape.palatable.lambda.functions.Fn0; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.builtin.fn2.Peek; import com.jnape.palatable.lambda.functions.builtin.fn2.Peek2; -import com.jnape.palatable.lambda.functions.specialized.checked.CheckedFn1; -import com.jnape.palatable.lambda.functions.specialized.checked.CheckedRunnable; -import com.jnape.palatable.lambda.functions.specialized.checked.CheckedSupplier; +import com.jnape.palatable.lambda.functions.specialized.SideEffect; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; -import java.util.function.BiFunction; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Supplier; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static java.util.Arrays.asList; /** @@ -30,7 +30,11 @@ * @param The left parameter type * @param The right parameter type */ -public abstract class Either implements CoProduct2>, Monad>, Traversable>, Bifunctor { +public abstract class Either implements + CoProduct2>, + Monad>, + Traversable>, + Bifunctor> { private Either() { } @@ -52,7 +56,7 @@ public final R or(R defaultValue) { * @param recoveryFn a function from L to R * @return either the wrapped value (if right) or the result of the left value applied to recoveryFn */ - public final R recover(Function recoveryFn) { + public final R recover(Fn1 recoveryFn) { return match(recoveryFn, id()); } @@ -63,7 +67,7 @@ public final R recover(Function recoveryFn) { * @param forfeitFn a function from R to L * @return either the wrapped value (if left) or the result of the right value applied to forfeitFn */ - public final L forfeit(Function forfeitFn) { + public final L forfeit(Fn1 forfeitFn) { return match(id(), forfeitFn); } @@ -71,13 +75,13 @@ public final L forfeit(Function forfeitFn) { * Return the wrapped value if this is a right; otherwise, map the wrapped left value to a T and throw * it. * - * @param throwableFn a function from L to T * @param the left parameter type (the throwable type) + * @param throwableFn a function from L to T * @return the wrapped value if this is a right * @throws T the result of applying the wrapped left value to throwableFn, if this is a left */ - public final R orThrow(Function throwableFn) throws T { - return match((CheckedFn1) l -> { + public final R orThrow(Fn1 throwableFn) throws T { + return match(l -> { throw throwableFn.apply(l); }, id()); } @@ -88,13 +92,13 @@ public final R orThrow(Function th *

* If this is a left value, return it. * - * @param pred the predicate to apply to a right value - * @param leftSupplier the supplier of a left value if pred fails + * @param pred the predicate to apply to a right value + * @param leftFn0 the supplier of a left value if pred fails * @return this if a left value or a right value that pred matches; otherwise, the result of leftSupplier wrapped in * a left */ - public final Either filter(Function pred, Supplier leftSupplier) { - return filter(pred, __ -> leftSupplier.get()); + public final Either filter(Fn1 pred, Fn0 leftFn0) { + return filter(pred, __ -> leftFn0.apply()); } /** @@ -106,8 +110,8 @@ public final Either filter(Function pred, Su * @return this is a left value or a right value that pred matches; otherwise, the result of leftFn applied to the * right value, wrapped in a left */ - public final Either filter(Function pred, - Function leftFn) { + public final Either filter(Fn1 pred, + Fn1 leftFn) { return flatMap(r -> pred.apply(r) ? right(r) : left(leftFn.apply(r))); } @@ -123,8 +127,9 @@ public final Either filter(Function pred, * @return the Either resulting from applying rightFn to this right value, or this left value if left */ @Override - public Either flatMap(Function>> rightFn) { - return match(Either::left, rightFn.andThen(Applicative::coerce)); + @SuppressWarnings("RedundantTypeArguments") + public Either flatMap(Fn1>> rightFn) { + return match(Either::left, rightFn.fmap(Monad>::coerce)); } @Override @@ -144,8 +149,9 @@ public final Either invert() { * @return the merged Either */ @SafeVarargs - public final Either merge(BiFunction leftFn, - BiFunction rightFn, + @SuppressWarnings("varargs") + public final Either merge(Fn2 leftFn, + Fn2 rightFn, Either... others) { return foldLeft((x, y) -> x.match(l1 -> y.match(l2 -> left(leftFn.apply(l1, l2)), r -> left(l1)), r1 -> y.match(Either::left, r2 -> right(rightFn.apply(r1, r2)))), @@ -156,22 +162,22 @@ public final Either merge(BiFunction le /** * Perform side-effects against a wrapped right value, returning back the Either unaltered. * - * @param rightConsumer the effecting consumer + * @param effect the effecting consumer * @return the Either, unaltered */ - public Either peek(Consumer rightConsumer) { - return Peek.peek(rightConsumer, this); + public Either peek(Fn1> effect) { + return Peek.peek(effect, this); } /** * Perform side-effects against a wrapped right or left value, returning back the Either unaltered. * - * @param leftConsumer the effecting consumer for left values - * @param rightConsumer the effecting consumer for right values + * @param leftEffect the effecting consumer for left values + * @param rightEffect the effecting consumer for right values * @return the Either, unaltered */ - public Either peek(Consumer leftConsumer, Consumer rightConsumer) { - return Peek2.peek2(leftConsumer, rightConsumer, this); + public Either peek(Fn1> leftEffect, Fn1> rightEffect) { + return Peek2.peek2(leftEffect, rightEffect, this); } /** @@ -179,67 +185,105 @@ public Either peek(Consumer leftConsumer, Consumer rightConsumer) { * V), unwrap the value stored in this Either, apply the appropriate mapping function, * and return the result. * + * @param the result type * @param leftFn the left value mapping function * @param rightFn the right value mapping function - * @param the result type * @return the result of applying the appropriate mapping function to the wrapped value */ @Override - public abstract V match(Function leftFn, Function rightFn); + public abstract V match(Fn1 leftFn, Fn1 rightFn); + /** + * {@inheritDoc} + */ @Override public Choice3 diverge() { return match(Choice3::a, Choice3::b); } + /** + * {@inheritDoc} + */ @Override - public final Either fmap(Function fn) { + public final Either fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override - @SuppressWarnings("unchecked") - public final Either biMapL(Function fn) { - return (Either) Bifunctor.super.biMapL(fn); + public final Either biMapL(Fn1 fn) { + return (Either) Bifunctor.super.biMapL(fn); } + /** + * {@inheritDoc} + */ @Override - @SuppressWarnings("unchecked") - public final Either biMapR(Function fn) { - return (Either) Bifunctor.super.biMapR(fn); + public final Either biMapR(Fn1 fn) { + return (Either) Bifunctor.super.biMapR(fn); } + /** + * {@inheritDoc} + */ @Override - public final Either biMap(Function leftFn, - Function rightFn) { + public final Either biMap(Fn1 leftFn, + Fn1 rightFn) { return match(l -> left(leftFn.apply(l)), r -> right(rightFn.apply(r))); } + /** + * {@inheritDoc} + */ @Override public final Either pure(R2 r2) { return right(r2); } + /** + * {@inheritDoc} + */ @Override - public final Either zip(Applicative, Either> appFn) { - return appFn.>>coerce().flatMap(this::biMapR); + public final Either zip(Applicative, Either> appFn) { + return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, Either>> lazyAppFn) { + return match(l -> lazy(left(l)), + r -> lazyAppFn.fmap(eitherLF -> eitherLF.fmap(f -> f.apply(r)).coerce())); + } + + /** + * {@inheritDoc} + */ @Override public final Either discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public final Either discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") - public final >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, - Function pure) { + public final , TravB extends Traversable>, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, + Fn1 pure) { return (AppTrav) match(l -> pure.apply((TravB) left(l)), r -> fn.apply(r).fmap(Either::right)); } @@ -257,71 +301,65 @@ public final Maybe toMaybe() { * Convert a {@link Maybe}<R> into an Either<L, R>, supplying the left value from * leftFn in the case of {@link Maybe#nothing()}. * - * @param maybe the maybe - * @param leftFn the supplier to use for left values - * @param the left parameter type - * @param the right parameter type + * @param the left parameter type + * @param the right parameter type + * @param maybe the maybe + * @param leftFn0 the supplier to use for left values * @return a right value of the contained maybe value, or a left value of leftFn's result */ - public static Either fromMaybe(Maybe maybe, Supplier leftFn) { + public static Either fromMaybe(Maybe maybe, Fn0 leftFn0) { return maybe.>fmap(Either::right) - .orElseGet(() -> left(leftFn.get())); + .orElseGet(() -> left(leftFn0.apply())); } /** - * Attempt to execute the {@link CheckedSupplier}, returning its result in a right value. If the supplier throws an + * Attempt to execute the {@link Fn0}, returning its result in a right value. If the supplier throws an * exception, apply leftFn to it, wrap it in a left value and return it. * - * @param supplier the supplier of the right value - * @param leftFn a function mapping E to L - * @param the most contravariant exception that the supplier might throw - * @param the left parameter type - * @param the right parameter type + * @param the left parameter type + * @param the right parameter type + * @param fn0 the supplier of the right value + * @param leftFn a function mapping E to L * @return the supplier result as a right value, or leftFn's mapping result as a left value */ - public static Either trying(CheckedSupplier supplier, - Function leftFn) { - return Try.trying(supplier::get).toEither(leftFn); + public static Either trying(Fn0 fn0, Fn1 leftFn) { + return Try.trying(fn0).toEither(leftFn); } /** - * Attempt to execute the {@link CheckedSupplier}, returning its result in a right value. If the supplier throws an + * Attempt to execute the {@link Fn0}, returning its result in a right value. If the supplier throws an * exception, wrap it in a left value and return it. * - * @param supplier the supplier of the right value - * @param the left parameter type (the most contravariant exception that supplier might throw) - * @param the right parameter type + * @param fn0 the supplier of the right value + * @param the right parameter type * @return the supplier result as a right value, or a left value of the thrown exception */ - public static Either trying(CheckedSupplier supplier) { - return trying(supplier, id()); + public static Either trying(Fn0 fn0) { + return trying(fn0, id()); } /** - * Attempt to execute the {@link CheckedRunnable}, returning {@link Unit} in a right value. If the runnable throws + * Attempt to execute the {@link SideEffect}, returning {@link Unit} in a right value. If the runnable throws * an exception, apply leftFn to it, wrap it in a left value, and return it. * - * @param runnable the runnable - * @param leftFn a function mapping E to L - * @param the most contravariant exception that the runnable might throw - * @param the left parameter type + * @param the left parameter type + * @param sideEffect the runnable + * @param leftFn a function mapping E to L * @return {@link Unit} as a right value, or leftFn's mapping result as a left value */ - public static Either trying(CheckedRunnable runnable, - Function leftFn) { - return Try.trying(runnable).toEither(leftFn); + public static Either trying(SideEffect sideEffect, Fn1 leftFn) { + return Try.trying(sideEffect).toEither(leftFn); } /** - * Attempt to execute the {@link CheckedRunnable}, returning {@link Unit} in a right value. If the runnable throws + * Attempt to execute the {@link SideEffect}, returning {@link Unit} in a right value. If the runnable throws * exception, wrap it in a left value and return it. * - * @param runnable the runnable - * @param the left parameter type (the most contravariant exception that runnable might throw) + * @param sideEffect the runnable * @return {@link Unit} as a right value, or a left value of the thrown exception */ - public static Either trying(CheckedRunnable runnable) { - return trying(runnable, id()); + public static Either trying(SideEffect sideEffect) { + return trying(sideEffect, id()); } /** @@ -356,7 +394,7 @@ private Left(L l) { } @Override - public V match(Function leftFn, Function rightFn) { + public V match(Fn1 leftFn, Fn1 rightFn) { return leftFn.apply(l); } @@ -386,7 +424,7 @@ private Right(R r) { } @Override - public V match(Function leftFn, Function rightFn) { + public V match(Fn1 leftFn, Fn1 rightFn) { return rightFn.apply(r); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java b/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java index ad0b81ad9..4cc726673 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java @@ -5,23 +5,25 @@ import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn0; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.Peek; -import com.jnape.palatable.lambda.functions.specialized.checked.CheckedSupplier; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Functor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; import java.util.Optional; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Supplier; import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.Unit.UNIT; +import static com.jnape.palatable.lambda.functions.Fn0.fn0; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** * The optional type, representing a potentially absent value. This is lambda's analog of {@link Optional}, supporting @@ -30,7 +32,10 @@ * @param the optional parameter type * @see Optional */ -public abstract class Maybe implements CoProduct2>, Monad, Traversable { +public abstract class Maybe implements + CoProduct2>, + Monad>, + Traversable> { private Maybe() { } @@ -38,11 +43,11 @@ private Maybe() { /** * If the value is present, return it; otherwise, return the value supplied by otherSupplier. * - * @param otherSupplier the supplier for the other value + * @param otherFn0 the supplier for the other value * @return this value, or the supplied other value */ - public final A orElseGet(Supplier otherSupplier) { - return match(__ -> otherSupplier.get(), id()); + public final A orElseGet(Fn0 otherFn0) { + return match(__ -> otherFn0.apply(), id()); } /** @@ -64,10 +69,10 @@ public final A orElse(A other) { * @return the value, if present * @throws E the throwable, if the value is absent */ - public final A orElseThrow(Supplier throwableSupplier) throws E { - return orElseGet((CheckedSupplier) () -> { - throw throwableSupplier.get(); - }); + public final A orElseThrow(Fn0 throwableSupplier) throws E { + return orElseGet(fn0(() -> { + throw throwableSupplier.apply(); + })); } /** @@ -77,7 +82,7 @@ public final A orElseThrow(Supplier throwableSupplier) * @param predicate the predicate to apply to the possibly absent value * @return maybe the present value that satisfied the predicate */ - public final Maybe filter(Function predicate) { + public final Maybe filter(Fn1 predicate) { return flatMap(a -> predicate.apply(a) ? just(a) : nothing()); } @@ -85,12 +90,12 @@ public final Maybe filter(Function predicate) { * If this value is absent, return the value supplied by lSupplier wrapped in Either.left. * Otherwise, wrap the value in Either.right and return it. * - * @param lSupplier the supplier for the left value - * @param the left parameter type + * @param the left parameter type + * @param lFn0 the supplier for the left value * @return this value wrapped in an Either.right, or an Either.left around the result of lSupplier */ - public final Either toEither(Supplier lSupplier) { - return fmap(Either::right).orElseGet(() -> left(lSupplier.get())); + public final Either toEither(Fn0 lFn0) { + return fmap(Either::right).orElseGet(() -> left(lFn0.apply())); } /** @@ -121,40 +126,75 @@ public final Maybe pure(B b) { * {@link Maybe#nothing}. */ @Override - public final Maybe fmap(Function fn) { + public final Maybe fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override - public final Maybe zip(Applicative, Maybe> appFn) { + public final Maybe zip(Applicative, Maybe> appFn) { return Monad.super.zip(appFn).coerce(); } + /** + * Terminate early if this is a {@link Nothing}; otherwise, continue the {@link Applicative#zip zip}. + * + * @param the result type + * @param lazyAppFn the lazy other applicative instance + * @return the zipped {@link Maybe} + */ + @Override + public Lazy> lazyZip(Lazy, Maybe>> lazyAppFn) { + return match(constantly(lazy(nothing())), + a -> lazyAppFn.fmap(maybeF -> maybeF.fmap(f -> f.apply(a)).coerce())); + } + + /** + * {@inheritDoc} + */ @Override - public final Maybe discardL(Applicative appB) { + public final Maybe discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override - public final Maybe discardR(Applicative appB) { + public final Maybe discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ + @SuppressWarnings("RedundantTypeArguments") @Override - public final Maybe flatMap(Function> f) { - return match(constantly(nothing()), f.andThen(Applicative::coerce)); + public final Maybe flatMap(Fn1>> f) { + return match(constantly(nothing()), f.fmap(Monad>::coerce)); } + /** + * {@inheritDoc} + */ @Override public Choice3 diverge() { return match(Choice3::a, Choice3::b); } + /** + * {@inheritDoc} + */ @Override public Tuple2, Maybe> project() { return CoProduct2.super.project().into(HList::tuple); } + /** + * {@inheritDoc} + */ @Override public Choice2 invert() { return match(Choice2::b, Choice2::a); @@ -163,18 +203,18 @@ public Choice2 invert() { /** * If this value is present, accept it by consumer; otherwise, do nothing. * - * @param consumer the consumer + * @param effect the consumer * @return the same Maybe instance */ - public final Maybe peek(Consumer consumer) { - return Peek.peek(consumer, this); + public final Maybe peek(Fn1> effect) { + return Peek.peek(effect, this); } @Override @SuppressWarnings("unchecked") - public final , AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, - Function pure) { + public final , TravB extends Traversable>, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, + Fn1 pure) { return match(__ -> pure.apply((TravB) Maybe.nothing()), a -> (AppTrav) fn.apply(a).fmap(Maybe::just)); } @@ -236,17 +276,17 @@ public static Maybe just(A a) { */ @SuppressWarnings("unchecked") public static Maybe nothing() { - return Nothing.INSTANCE; + return (Maybe) Nothing.INSTANCE; } private static final class Nothing extends Maybe { - private static final Nothing INSTANCE = new Nothing(); + private static final Nothing INSTANCE = new Nothing<>(); private Nothing() { } @Override - public R match(Function aFn, Function bFn) { + public R match(Fn1 aFn, Fn1 bFn) { return aFn.apply(UNIT); } @@ -265,7 +305,7 @@ private Just(A a) { } @Override - public R match(Function aFn, Function bFn) { + public R match(Fn1 aFn, Fn1 bFn) { return bFn.apply(a); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/These.java b/src/main/java/com/jnape/palatable/lambda/adt/These.java index f4ffc5846..5f8e67270 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/These.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/These.java @@ -3,17 +3,19 @@ import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; import com.jnape.palatable.lambda.adt.coproduct.CoProduct3; import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; -import java.util.function.Function; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** * The coproduct of a coproduct ({@link CoProduct2}<A, B>) and its product ({@link @@ -23,7 +25,11 @@ * @param the first possible type * @param the second possible type */ -public abstract class These implements CoProduct3, These>, Monad>, Bifunctor>, Traversable> { +public abstract class These implements + CoProduct3, These>, + Monad>, + Bifunctor>, + Traversable> { private These() { } @@ -32,8 +38,8 @@ private These() { * {@inheritDoc} */ @Override - public final These biMap(Function lFn, - Function rFn) { + public final These biMap(Fn1 lFn, + Fn1 rFn) { return match(a -> a(lFn.apply(a)), b -> b(rFn.apply(b)), into((a, b) -> both(lFn.apply(a), rFn.apply(b)))); } @@ -41,7 +47,7 @@ public final These biMap(Function lFn, * {@inheritDoc} */ @Override - public final These flatMap(Function>> f) { + public final These flatMap(Fn1>> f) { return match(These::a, b -> f.apply(b).coerce(), into((a, b) -> f.apply(b).>coerce().biMapL(constantly(a)))); } @@ -55,8 +61,9 @@ public final These pure(C c) { @Override @SuppressWarnings("unchecked") - public >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public , TravB extends Traversable>, + AppTrav extends Applicative> + AppTrav traverse(Fn1> fn, Fn1 pure) { return match(a -> pure.apply((TravB) a(a)), b -> fn.apply(b).fmap(this::pure).fmap(Applicative::coerce).coerce(), into((a, b) -> fn.apply(b).fmap(c -> both(a, c)).fmap(Applicative::coerce).coerce())); @@ -67,7 +74,7 @@ public final These pure(C c) { */ @Override @SuppressWarnings("unchecked") - public final These biMapL(Function fn) { + public final These biMapL(Fn1 fn) { return (These) Bifunctor.super.biMapL(fn); } @@ -76,7 +83,7 @@ public final These biMapL(Function fn) { */ @Override @SuppressWarnings("unchecked") - public final These biMapR(Function fn) { + public final These biMapR(Fn1 fn) { return (These) Bifunctor.super.biMapR(fn); } @@ -84,7 +91,7 @@ public final These biMapR(Function fn) { * {@inheritDoc} */ @Override - public final These fmap(Function fn) { + public final These fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } @@ -92,10 +99,17 @@ public final These fmap(Function fn) { * {@inheritDoc} */ @Override - public final These zip(Applicative, These> appFn) { + public final These zip(Applicative, These> appFn) { return Monad.super.zip(appFn).coerce(); } + @Override + public Lazy> lazyZip( + Lazy, These>> lazyAppFn) { + return projectA().>>fmap(a -> lazy(a(a))) + .orElseGet(() -> Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce)); + } + /** * {@inheritDoc} */ @@ -159,8 +173,8 @@ private _A(A a) { } @Override - public R match(Function aFn, Function bFn, - Function, ? extends R> cFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1, ? extends R> cFn) { return aFn.apply(a); } @@ -188,8 +202,8 @@ private _B(B b) { } @Override - public R match(Function aFn, Function bFn, - Function, ? extends R> cFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1, ? extends R> cFn) { return bFn.apply(b); } @@ -217,8 +231,8 @@ private Both(Tuple2 tuple) { } @Override - public R match(Function aFn, Function bFn, - Function, ? extends R> cFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1, ? extends R> cFn) { return cFn.apply(both); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Try.java b/src/main/java/com/jnape/palatable/lambda/adt/Try.java index d629a967b..bdc2ec040 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Try.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Try.java @@ -1,33 +1,33 @@ package com.jnape.palatable.lambda.adt; import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; -import com.jnape.palatable.lambda.functions.specialized.checked.CheckedFn1; -import com.jnape.palatable.lambda.functions.specialized.checked.CheckedRunnable; -import com.jnape.palatable.lambda.functions.specialized.checked.CheckedSupplier; +import com.jnape.palatable.lambda.functions.Fn0; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.SideEffect; import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.functor.BoundedBifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; -import java.util.function.Function; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.functions.builtin.fn1.Upcast.upcast; -import static com.jnape.palatable.lambda.functions.builtin.fn2.Peek2.peek2; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; +import static com.jnape.palatable.lambda.internal.Runtime.throwChecked; /** * A {@link Monad} of the evaluation outcome of an expression that might throw. Try/catch/finally semantics map to * trying/catching/ensuring, respectively. * - * @param the {@link Throwable} type that may have been thrown by the expression * @param the possibly successful expression result * @see Either */ -public abstract class Try implements Monad>, Traversable>, BoundedBifunctor>, CoProduct2> { +public abstract class Try implements Monad>, Traversable>, CoProduct2> { private Try() { } @@ -35,13 +35,14 @@ private Try() { /** * Catch any instance of throwableType and map it to a success value. * + * @param the {@link Throwable} (sub)type * @param throwableType the {@link Throwable} (sub)type to be caught * @param recoveryFn the function mapping the {@link Throwable} to the result - * @param the {@link Throwable} (sub)type * @return a new {@link Try} instance around either the original successful result or the mapped result */ @SuppressWarnings("unchecked") - public final Try catching(Class throwableType, Function recoveryFn) { + public final Try catching(Class throwableType, + Fn1 recoveryFn) { return catching(throwableType::isInstance, t -> recoveryFn.apply((S) t)); } @@ -52,8 +53,8 @@ public final Try catching(Class throwableType, Function catching(Function predicate, - Function recoveryFn) { + public final Try catching(Fn1 predicate, + Fn1 recoveryFn) { return match(t -> predicate.apply(t) ? success(recoveryFn.apply(t)) : failure(t), Try::success); } @@ -66,15 +67,18 @@ public final Try catching(Function predicate * over some {@link Throwable} t1, and the runnable throws a new {@link Throwable} t2, the * result is a failure over t1 with t2 added to t1 as a suppressed exception. * - * @param runnable the runnable block of code to execute + * @param sideEffect the runnable block of code to execute * @return the same {@link Try} instance if runnable completes successfully; otherwise, a {@link Try} conforming to * rules above */ - public final Try ensuring(CheckedRunnable runnable) { - return match(t -> peek2(t::addSuppressed, __ -> {}, trying(runnable)) - .biMapL(constantly(t)) - .flatMap(constantly(failure(t))), - a -> trying(runnable).fmap(constantly(a))); + public final Try ensuring(SideEffect sideEffect) { + return match(t -> trying(sideEffect) + .>fmap(constantly(failure(t))) + .recover(t2 -> { + t.addSuppressed(t2); + return failure(t); + }), + a -> trying(sideEffect).fmap(constantly(a))); } /** @@ -84,7 +88,7 @@ public final Try ensuring(CheckedRunnable runnable) { * @param fn the function mapping the potential {@link Throwable} T to A * @return a success value */ - public final A recover(Function fn) { + public final A recover(Fn1 fn) { return match(fn, id()); } @@ -95,17 +99,36 @@ public final A recover(Function fn) { * @param fn the function mapping the potential A to T * @return a failure value */ - public final T forfeit(Function fn) { + public final Throwable forfeit(Fn1 fn) { return match(id(), fn); } /** * If this is a success value, return it. Otherwise, rethrow the captured failure. * + * @param a declarable exception type used for catching checked exceptions + * @return possibly the success value + * @throws T anything that the call site may want to explicitly catch or indicate could be thrown + */ + public final A orThrow() throws T { + try { + return orThrow(id()); + } catch (Throwable t) { + throw throwChecked(t); + } + } + + /** + * If this is a success value, return it. Otherwise, transform the captured failure with fn and throw + * the result. + * + * @param fn the {@link Throwable} transformation + * @param the type of the thrown {@link Throwable} * @return possibly the success value - * @throws T the possible failure + * @throws T the transformation output */ - public abstract A orThrow() throws T; + public abstract A orThrow(Fn1 fn) throws T; + /** * If this is a success, wrap the value in a {@link Maybe#just} and return it. Otherwise, return {@link @@ -123,7 +146,7 @@ public final Maybe toMaybe() { * * @return {@link Either} the success value or the {@link Throwable} */ - public final Either toEither() { + public final Either toEither() { return toEither(id()); } @@ -131,89 +154,102 @@ public final Either toEither() { * If this is a success, wrap the value in a {@link Either#right} and return it. Otherwise, apply the mapping * function to the failure {@link Throwable}, re-wrap it in an {@link Either#left}, and return it. * - * @param fn the mapping function * @param the {@link Either} left parameter type + * @param fn the mapping function * @return {@link Either} the success value or the mapped left value */ - public final Either toEither(Function fn) { - return match(fn.andThen(Either::left), Either::right); + public final Either toEither(Fn1 fn) { + return match(fn.fmap(Either::left), Either::right); } + /** + * {@inheritDoc} + */ @Override - public Try fmap(Function fn) { + public Try fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override - public Try flatMap(Function>> f) { + public Try flatMap(Fn1>> f) { return match(Try::failure, a -> f.apply(a).coerce()); } + /** + * {@inheritDoc} + */ @Override - public Try pure(B b) { + public Try pure(B b) { return success(b); } + /** + * {@inheritDoc} + */ @Override - public Try zip(Applicative, Try> appFn) { + public Try zip(Applicative, Try> appFn) { return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ @Override - public Try discardL(Applicative> appB) { + public Lazy> lazyZip(Lazy, Try>> lazyAppFn) { + return match(f -> lazy(failure(f)), + s -> lazyAppFn.fmap(tryF -> tryF.fmap(f -> f.apply(s)).coerce())); + } + + /** + * {@inheritDoc} + */ + @Override + public Try discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override - public Try discardR(Applicative> appB) { + public Try discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") - public >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public , TravB extends Traversable>, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, + Fn1 pure) { return match(t -> pure.apply((TravB) failure(t)), a -> fn.apply(a).fmap(Try::success).fmap(Applicative::coerce).coerce()); } - @Override - public Try biMap(Function lFn, - Function rFn) { - return match(t -> failure(lFn.apply(t)), a -> success(rFn.apply(a))); - } - - @Override - public Try biMapL(Function fn) { - return (Try) BoundedBifunctor.super.biMapL(fn); - } - - @Override - public Try biMapR(Function fn) { - return (Try) BoundedBifunctor.super.biMapR(fn); - } - /** * Static factory method for creating a success value. * * @param a the wrapped value - * @param the failure parameter type * @param the success parameter type * @return a success value of a */ - public static Try success(A a) { + public static Try success(A a) { return new Success<>(a); } /** * Static factory method for creating a failure value. * - * @param t the wrapped {@link Throwable} - * @param the failure parameter type + * @param t the {@link Throwable} * @param the success parameter type * @return a failure value of t */ - public static Try failure(T t) { + public static Try failure(Throwable t) { return new Failure<>(t); } @@ -221,37 +257,34 @@ public static Try failure(T t) { * Execute supplier, returning a success A or a failure of the thrown {@link Throwable}. * * @param supplier the supplier - * @param the possible {@link Throwable} type * @param the possible success type * @return a new {@link Try} around either a successful A result or the thrown {@link Throwable} */ - @SuppressWarnings("unchecked") - public static Try trying(CheckedSupplier supplier) { + public static Try trying(Fn0 supplier) { try { - return success(supplier.get()); + return success(supplier.apply()); } catch (Throwable t) { - return failure((T) t); + return failure(t); } } /** * Execute runnable, returning a success {@link Unit} or a failure of the thrown {@link Throwable}. * - * @param runnable the runnable - * @param the possible {@link Throwable} type + * @param sideEffect the runnable * @return a new {@link Try} around either a successful {@link Unit} result or the thrown {@link Throwable} */ - public static Try trying(CheckedRunnable runnable) { + public static Try trying(SideEffect sideEffect) { return trying(() -> { - runnable.run(); + IO.io(sideEffect).unsafePerformIO(); return UNIT; }); } /** - * Given a {@link CheckedSupplier}<{@link AutoCloseable}> aSupplier and a - * {@link Function} fn, apply fn to the result of aSupplier, ensuring - * that the result has its {@link AutoCloseable#close() close} method invoked, regardless of the outcome. + * Given a {@link Fn0}<{@link AutoCloseable}> aSupplier and an {@link Fn1} + * fn, apply fn to the result of aSupplier, ensuring that the result has its + * {@link AutoCloseable#close() close} method invoked, regardless of the outcome. *

* If the resource creation process throws, the function body throws, or the * {@link AutoCloseable#close() close method} throws, the result is a failure. If both the function body and the @@ -269,78 +302,79 @@ public static Try trying(CheckedRunnable runna * * try-with-resources, introduced in Java 7. * - * @param aSupplier the resource supplier - * @param fn the function body - * @param the resource type - * @param the function return type + * @param fn0 the resource supplier + * @param fn the function body + * @param the resource type + * @param the function return type * @return a {@link Try} representing the result of the function's application to the resource */ - public static Try withResources( - CheckedSupplier aSupplier, - CheckedFn1> fn) { + @SuppressWarnings("try") + public static Try withResources( + Fn0 fn0, + Fn1> fn) { return trying(() -> { - try (A resource = aSupplier.get()) { - return fn.apply(resource).biMap(upcast(), upcast()); + try (A resource = fn0.apply()) { + return fn.apply(resource).fmap(upcast()); } }).flatMap(id()); } /** - * Convenience overload of {@link Try#withResources(CheckedSupplier, CheckedFn1) withResources} that cascades - * dependent resource creation via nested calls. + * Convenience overload of {@link Try#withResources(Fn0, Fn1) withResources} that cascades dependent resource + * creation via nested calls. * - * @param aSupplier the first resource supplier - * @param bFn the dependent resource function - * @param fn the function body - * @param the first resource type - * @param the second resource type - * @param the function return type + * @param fn0 the first resource supplier + * @param bFn the dependent resource function + * @param fn the function body + * @param the first resource type + * @param the second resource type + * @param the function return type * @return a {@link Try} representing the result of the function's application to the dependent resource */ - public static Try withResources( - CheckedSupplier aSupplier, - CheckedFn1 bFn, - CheckedFn1> fn) { - return withResources(aSupplier, a -> withResources(() -> bFn.apply(a), fn::apply)); + public static Try withResources( + Fn0 fn0, + Fn1 bFn, + Fn1> fn) { + return withResources(fn0, a -> withResources(() -> bFn.apply(a), fn::apply)); } /** - * Convenience overload of {@link Try#withResources(CheckedSupplier, CheckedFn1, CheckedFn1) withResources} that + * Convenience overload of {@link Try#withResources(Fn0, Fn1, Fn1) withResources} that * cascades * two dependent resource creations via nested calls. * - * @param aSupplier the first resource supplier - * @param bFn the second resource function - * @param cFn the final resource function - * @param fn the function body - * @param the first resource type - * @param the second resource type - * @param the final resource type - * @param the function return type + * @param fn0 the first resource supplier + * @param bFn the second resource function + * @param cFn the final resource function + * @param fn the function body + * @param the first resource type + * @param the second resource type + * @param the final resource type + * @param the function return type * @return a {@link Try} representing the result of the function's application to the final dependent resource */ - public static Try withResources( - CheckedSupplier aSupplier, - CheckedFn1 bFn, - CheckedFn1 cFn, - CheckedFn1> fn) { - return withResources(aSupplier, bFn, b -> withResources(() -> cFn.apply(b), fn::apply)); + public static Try withResources( + Fn0 fn0, + Fn1 bFn, + Fn1 cFn, + Fn1> fn) { + return withResources(fn0, bFn, b -> withResources(() -> cFn.apply(b), fn::apply)); } - private static final class Failure extends Try { - private final T t; + private static final class Failure extends Try { + private final Throwable t; - private Failure(T t) { + private Failure(Throwable t) { this.t = t; } @Override - public A orThrow() throws T { - throw t; + public A orThrow(Fn1 fn) throws T { + throw fn.apply(t); } @Override - public R match(Function aFn, Function bFn) { + public R match(Fn1 aFn, Fn1 bFn) { return aFn.apply(t); } @@ -362,7 +396,7 @@ public String toString() { } } - private static final class Success extends Try { + private static final class Success extends Try { private final A a; private Success(A a) { @@ -370,12 +404,12 @@ private Success(A a) { } @Override - public A orThrow() throws T { + public A orThrow(Fn1 fn) { return a; } @Override - public R match(Function aFn, Function bFn) { + public R match(Fn1 aFn, Fn1 bFn) { return bFn.apply(a); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java index 969da832d..7366881c2 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java @@ -5,15 +5,18 @@ import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.Functor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** * Canonical ADT representation of {@link CoProduct2}. Unlike {@link Either}, there is no concept of "success" or @@ -27,7 +30,7 @@ public abstract class Choice2 implements CoProduct2>, Monad>, - Bifunctor, + Bifunctor>, Traversable> { private Choice2() { @@ -43,71 +46,115 @@ public Tuple2, Maybe> project() { return into(HList::tuple, CoProduct2.super.project()); } + /** + * {@inheritDoc} + */ @Override public final Choice3 diverge() { return match(Choice3::a, Choice3::b); } + /** + * {@inheritDoc} + */ @Override public Choice2 invert() { return match(Choice2::b, Choice2::a); } + /** + * {@inheritDoc} + */ @Override - public final Choice2 fmap(Function fn) { + public final Choice2 fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override - @SuppressWarnings("unchecked") - public final Choice2 biMapL(Function fn) { - return (Choice2) Bifunctor.super.biMapL(fn); + public final Choice2 biMapL(Fn1 fn) { + return (Choice2) Bifunctor.super.biMapL(fn); } + /** + * {@inheritDoc} + */ @Override - @SuppressWarnings("unchecked") - public final Choice2 biMapR(Function fn) { - return (Choice2) Bifunctor.super.biMapR(fn); + public final Choice2 biMapR(Fn1 fn) { + return (Choice2) Bifunctor.super.biMapR(fn); } + /** + * {@inheritDoc} + */ @Override - public final Choice2 biMap(Function lFn, - Function rFn) { + public final Choice2 biMap(Fn1 lFn, + Fn1 rFn) { return match(a -> a(lFn.apply(a)), b -> b(rFn.apply(b))); } + /** + * {@inheritDoc} + */ @Override public Choice2 pure(C c) { return b(c); } + /** + * {@inheritDoc} + */ @Override - public Choice2 zip(Applicative, Choice2> appFn) { - return appFn.>>coerce() - .match(Choice2::a, this::biMapR); + public Choice2 zip(Applicative, Choice2> appFn) { + return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ + @Override + public Lazy>> lazyZip( + Lazy, Choice2>> lazyAppFn) { + return match(a -> lazy(a(a)), + b -> lazyAppFn.fmap(choiceF -> choiceF.fmap(f -> f.apply(b)).coerce())); + } + + /** + * {@inheritDoc} + */ @Override public Choice2 discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Choice2 discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override - public final Choice2 flatMap(Function>> f) { + public final Choice2 flatMap(Fn1>> f) { return match(Choice2::a, b -> f.apply(b).coerce()); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") - public >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public , TravB extends Traversable>, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, + Fn1 pure) { return match(a -> pure.apply((TravB) a(a)), - b -> fn.apply(b).fmap(Choice2::b).fmap(Applicative::coerce).coerce()); + b -> fn.apply(b).>fmap(Choice2::b).fmap(Functor::coerce).coerce()); } /** @@ -143,7 +190,7 @@ private _A(A a) { } @Override - public R match(Function aFn, Function bFn) { + public R match(Fn1 aFn, Fn1 bFn) { return aFn.apply(a); } @@ -175,7 +222,7 @@ private _B(B b) { } @Override - public R match(Function aFn, Function bFn) { + public R match(Fn1 aFn, Fn1 bFn) { return bFn.apply(b); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java index 1f8aa3226..5e4388419 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java @@ -5,15 +5,18 @@ import com.jnape.palatable.lambda.adt.coproduct.CoProduct3; import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple3; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.Functor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into3.into3; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** * Canonical ADT representation of {@link CoProduct3}. @@ -43,72 +46,117 @@ public Tuple3, Maybe, Maybe> project() { return into3(HList::tuple, CoProduct3.super.project()); } + /** + * {@inheritDoc} + */ @Override public final Choice4 diverge() { return match(Choice4::a, Choice4::b, Choice4::c); } + /** + * {@inheritDoc} + */ @Override - public final Choice2 converge(Function> convergenceFn) { - return match(Choice2::a, Choice2::b, convergenceFn.andThen(cp2 -> cp2.match(Choice2::a, Choice2::b))); + public final Choice2 converge(Fn1> convergenceFn) { + return match(Choice2::a, Choice2::b, convergenceFn.fmap(cp2 -> cp2.match(Choice2::a, Choice2::b))); } + /** + * {@inheritDoc} + */ @Override - public final Choice3 fmap(Function fn) { + public final Choice3 fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override - @SuppressWarnings("unchecked") - public final Choice3 biMapL(Function fn) { - return (Choice3) Bifunctor.super.biMapL(fn); + public final Choice3 biMapL(Fn1 fn) { + return (Choice3) Bifunctor.super.biMapL(fn); } + /** + * {@inheritDoc} + */ @Override - @SuppressWarnings("unchecked") - public final Choice3 biMapR(Function fn) { - return (Choice3) Bifunctor.super.biMapR(fn); + public final Choice3 biMapR(Fn1 fn) { + return (Choice3) Bifunctor.super.biMapR(fn); } + /** + * {@inheritDoc} + */ @Override - public final Choice3 biMap(Function lFn, - Function rFn) { + public final Choice3 biMap(Fn1 lFn, + Fn1 rFn) { return match(Choice3::a, b -> b(lFn.apply(b)), c -> c(rFn.apply(c))); } + /** + * {@inheritDoc} + */ @Override public Choice3 pure(D d) { return c(d); } + /** + * {@inheritDoc} + */ @Override - public Choice3 zip(Applicative, Choice3> appFn) { - return appFn.>>coerce() - .match(Choice3::a, Choice3::b, this::biMapR); + public Choice3 zip(Applicative, Choice3> appFn) { + return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, Choice3>> lazyAppFn) { + return match(a -> lazy(a(a)), + b -> lazy(b(b)), + c -> lazyAppFn.fmap(choiceF -> choiceF.fmap(f -> f.apply(c)).coerce())); + } + + /** + * {@inheritDoc} + */ @Override public Choice3 discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Choice3 discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override - public Choice3 flatMap(Function>> f) { + public Choice3 flatMap(Fn1>> f) { return match(Choice3::a, Choice3::b, c -> f.apply(c).coerce()); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") - public >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public , TravB extends Traversable>, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, + Fn1 pure) { return match(a -> pure.apply((TravB) Choice3.a(a)).coerce(), b -> pure.apply((TravB) Choice3.b(b)).coerce(), - c -> fn.apply(c).fmap(Choice3::c).fmap(Applicative::coerce).coerce()); + c -> fn.apply(c).>fmap(Choice3::c).fmap(Functor::coerce).coerce()); } /** @@ -159,8 +207,8 @@ private _A(A a) { } @Override - public R match(Function aFn, Function bFn, - Function cFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn) { return aFn.apply(a); } @@ -192,8 +240,8 @@ private _B(B b) { } @Override - public R match(Function aFn, Function bFn, - Function cFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn) { return bFn.apply(b); } @@ -225,8 +273,8 @@ private _C(C c) { } @Override - public R match(Function aFn, Function bFn, - Function cFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn) { return cFn.apply(c); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java index 494638330..4f79f3d5e 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java @@ -5,15 +5,18 @@ import com.jnape.palatable.lambda.adt.coproduct.CoProduct4; import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple4; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.Functor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into4.into4; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** * Canonical ADT representation of {@link CoProduct4}. @@ -44,76 +47,117 @@ public Tuple4, Maybe, Maybe, Maybe> project() { return into4(HList::tuple, CoProduct4.super.project()); } + /** + * {@inheritDoc} + */ @Override public Choice5 diverge() { return match(Choice5::a, Choice5::b, Choice5::c, Choice5::d); } + /** + * {@inheritDoc} + */ @Override - public Choice3 converge(Function> convergenceFn) { - return match(Choice3::a, - Choice3::b, - Choice3::c, - convergenceFn.andThen(cp3 -> cp3.match(Choice3::a, Choice3::b, Choice3::c))); + public Choice3 converge(Fn1> convergenceFn) { + return match(Choice3::a, Choice3::b, Choice3::c, + convergenceFn.fmap(cp3 -> cp3.match(Choice3::a, Choice3::b, Choice3::c))); } + /** + * {@inheritDoc} + */ @Override - public final Choice4 fmap(Function fn) { + public final Choice4 fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override - @SuppressWarnings("unchecked") - public final Choice4 biMapL(Function fn) { - return (Choice4) Bifunctor.super.biMapL(fn); + public final Choice4 biMapL(Fn1 fn) { + return (Choice4) Bifunctor.super.biMapL(fn); } + /** + * {@inheritDoc} + */ @Override - @SuppressWarnings("unchecked") - public final Choice4 biMapR(Function fn) { - return (Choice4) Bifunctor.super.biMapR(fn); + public final Choice4 biMapR(Fn1 fn) { + return (Choice4) Bifunctor.super.biMapR(fn); } @Override - public final Choice4 biMap(Function lFn, - Function rFn) { + public final Choice4 biMap(Fn1 lFn, + Fn1 rFn) { return match(Choice4::a, Choice4::b, c -> c(lFn.apply(c)), d -> d(rFn.apply(d))); } + /** + * {@inheritDoc} + */ @Override public Choice4 pure(E e) { return d(e); } + /** + * {@inheritDoc} + */ @Override - public Choice4 zip(Applicative, Choice4> appFn) { - return appFn.>>coerce() - .match(Choice4::a, Choice4::b, Choice4::c, this::biMapR); + public Choice4 zip(Applicative, Choice4> appFn) { + return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, Choice4>> lazyAppFn) { + return match(a -> lazy(a(a)), + b -> lazy(b(b)), + c -> lazy(c(c)), + d -> lazyAppFn.fmap(choiceF -> choiceF.fmap(f -> f.apply(d)).coerce())); + } + + /** + * {@inheritDoc} + */ @Override public Choice4 discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Choice4 discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override - public Choice4 flatMap(Function>> f) { + public Choice4 flatMap(Fn1>> f) { return match(Choice4::a, Choice4::b, Choice4::c, d -> f.apply(d).coerce()); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") - public >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public , TravB extends Traversable>, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, + Fn1 pure) { return match(a -> pure.apply((TravB) Choice4.a(a)).coerce(), b -> pure.apply((TravB) Choice4.b(b)).coerce(), c -> pure.apply((TravB) Choice4.c(c)), - d -> fn.apply(d).fmap(Choice4::d).fmap(Applicative::coerce).coerce()); + d -> fn.apply(d).>fmap(Choice4::d).fmap(Functor::coerce).coerce()); } /** @@ -181,8 +225,8 @@ private _A(A a) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn) { return aFn.apply(a); } @@ -214,8 +258,8 @@ private _B(B b) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn) { return bFn.apply(b); } @@ -247,8 +291,8 @@ private _C(C c) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn) { return cFn.apply(c); } @@ -280,8 +324,8 @@ private _D(D d) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn) { return dFn.apply(d); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java index 5954d4ae2..8714e4395 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java @@ -5,15 +5,17 @@ import com.jnape.palatable.lambda.adt.coproduct.CoProduct5; import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple5; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into5.into5; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** * Canonical ADT representation of {@link CoProduct5}. @@ -45,78 +47,123 @@ public Tuple5, Maybe, Maybe, Maybe, Maybe> project() { return into5(HList::tuple, CoProduct5.super.project()); } + /** + * {@inheritDoc} + */ @Override public Choice6 diverge() { return match(Choice6::a, Choice6::b, Choice6::c, Choice6::d, Choice6::e); } + /** + * {@inheritDoc} + */ @Override - public Choice4 converge(Function> convergenceFn) { - return match(Choice4::a, - Choice4::b, - Choice4::c, - Choice4::d, - convergenceFn.andThen(cp4 -> cp4.match(Choice4::a, Choice4::b, Choice4::c, Choice4::d))); + public Choice4 converge(Fn1> convergenceFn) { + return match(Choice4::a, Choice4::b, Choice4::c, Choice4::d, + convergenceFn.fmap(cp4 -> cp4.match(Choice4::a, Choice4::b, Choice4::c, Choice4::d))); } + /** + * {@inheritDoc} + */ @Override - public Choice5 fmap(Function fn) { + public Choice5 fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override - @SuppressWarnings("unchecked") - public Choice5 biMapL(Function fn) { - return (Choice5) Bifunctor.super.biMapL(fn); + public Choice5 biMapL(Fn1 fn) { + return (Choice5) Bifunctor.super.biMapL(fn); } + /** + * {@inheritDoc} + */ @Override - @SuppressWarnings("unchecked") - public Choice5 biMapR(Function fn) { - return (Choice5) Bifunctor.super.biMapR(fn); + public Choice5 biMapR(Fn1 fn) { + return (Choice5) Bifunctor.super.biMapR(fn); } + /** + * {@inheritDoc} + */ @Override - public Choice5 biMap(Function lFn, - Function rFn) { + public Choice5 biMap(Fn1 lFn, + Fn1 rFn) { return match(Choice5::a, Choice5::b, Choice5::c, d -> d(lFn.apply(d)), e -> e(rFn.apply(e))); } + /** + * {@inheritDoc} + */ @Override public Choice5 pure(F f) { return e(f); } + /** + * {@inheritDoc} + */ @Override - public Choice5 zip(Applicative, Choice5> appFn) { - return appFn.>>coerce() - .match(Choice5::a, Choice5::b, Choice5::c, Choice5::d, this::biMapR); + public Choice5 zip(Applicative, Choice5> appFn) { + return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, Choice5>> lazyAppFn) { + return match(a -> lazy(a(a)), + b -> lazy(b(b)), + c -> lazy(c(c)), + d -> lazy(d(d)), + e -> lazyAppFn.fmap(choiceF -> choiceF.fmap(f -> f.apply(e)).coerce())); + } + + /** + * {@inheritDoc} + */ @Override public Choice5 discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Choice5 discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override - public Choice5 flatMap(Function>> f) { + public Choice5 flatMap(Fn1>> f) { return match(Choice5::a, Choice5::b, Choice5::c, Choice5::d, e -> f.apply(e).coerce()); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") - public >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public , TravB extends Traversable>, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, + Fn1 pure) { return match(a -> pure.apply((TravB) Choice5.a(a)).coerce(), b -> pure.apply((TravB) Choice5.b(b)).coerce(), c -> pure.apply((TravB) Choice5.c(c)), d -> pure.apply((TravB) Choice5.d(d)), - e -> fn.apply(e).fmap(Choice5::e).fmap(Applicative::coerce).coerce()); + e -> fn.apply(e).>fmap(Choice5::e) + .fmap(Applicative::coerce).coerce()); } /** @@ -203,9 +250,9 @@ private _A(A a) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn) { return aFn.apply(a); } @@ -237,9 +284,9 @@ private _B(B b) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn) { return bFn.apply(b); } @@ -271,9 +318,9 @@ private _C(C c) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn) { return cFn.apply(c); } @@ -305,9 +352,9 @@ private _D(D d) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn) { return dFn.apply(d); } @@ -339,9 +386,9 @@ private _E(E e) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn) { return eFn.apply(e); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java index 8076383b8..ff2ba8df5 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java @@ -5,15 +5,17 @@ import com.jnape.palatable.lambda.adt.coproduct.CoProduct6; import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple6; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into6.into6; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** * Canonical ADT representation of {@link CoProduct6}. @@ -46,82 +48,128 @@ public Tuple6, Maybe, Maybe, Maybe, Maybe, Maybe> projec return into6(HList::tuple, CoProduct6.super.project()); } + /** + * {@inheritDoc} + */ @Override public Choice7 diverge() { return match(Choice7::a, Choice7::b, Choice7::c, Choice7::d, Choice7::e, Choice7::f); } + /** + * {@inheritDoc} + */ @Override - public Choice5 converge(Function> convergenceFn) { - return match(Choice5::a, - Choice5::b, - Choice5::c, - Choice5::d, - Choice5::e, - convergenceFn.andThen(cp5 -> cp5.match(Choice5::a, Choice5::b, Choice5::c, Choice5::d, Choice5::e))); + public Choice5 converge(Fn1> convergenceFn) { + return match(Choice5::a, Choice5::b, Choice5::c, Choice5::d, Choice5::e, + convergenceFn.fmap(cp5 -> cp5.match(Choice5::a, Choice5::b, Choice5::c, Choice5::d, Choice5::e))); } + /** + * {@inheritDoc} + */ @Override - public Choice6 fmap(Function fn) { + public Choice6 fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") - public Choice6 biMapL(Function fn) { + public Choice6 biMapL(Fn1 fn) { return (Choice6) Bifunctor.super.biMapL(fn); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") - public Choice6 biMapR(Function fn) { + public Choice6 biMapR(Fn1 fn) { return (Choice6) Bifunctor.super.biMapR(fn); } + /** + * {@inheritDoc} + */ @Override - public Choice6 biMap(Function lFn, - Function rFn) { + public Choice6 biMap(Fn1 lFn, + Fn1 rFn) { return match(Choice6::a, Choice6::b, Choice6::c, Choice6::d, e -> e(lFn.apply(e)), f -> f(rFn.apply(f))); } + /** + * {@inheritDoc} + */ @Override public Choice6 pure(G g) { return f(g); } + /** + * {@inheritDoc} + */ @Override public Choice6 zip( - Applicative, Choice6> appFn) { - return appFn.>>coerce() - .match(Choice6::a, Choice6::b, Choice6::c, Choice6::d, Choice6::e, this::biMapR); + Applicative, Choice6> appFn) { + return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, Choice6>> lazyAppFn) { + return match(a -> lazy(a(a)), + b -> lazy(b(b)), + c -> lazy(c(c)), + d -> lazy(d(d)), + e -> lazy(e(e)), + f -> lazyAppFn.fmap(choiceFn -> choiceFn.fmap(fn -> fn.apply(f)).coerce())); + } + + /** + * {@inheritDoc} + */ @Override public Choice6 discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Choice6 discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override - public Choice6 flatMap( - Function>> fn) { + public Choice6 flatMap(Fn1>> fn) { return match(Choice6::a, Choice6::b, Choice6::c, Choice6::d, Choice6::e, f -> fn.apply(f).coerce()); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") - public >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public , TravB extends Traversable>, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, + Fn1 pure) { return match(a -> pure.apply((TravB) Choice6.a(a)).coerce(), b -> pure.apply((TravB) Choice6.b(b)).coerce(), c -> pure.apply((TravB) Choice6.c(c)), d -> pure.apply((TravB) Choice6.d(d)), e -> pure.apply((TravB) Choice6.e(e)), - f -> fn.apply(f).fmap(Choice6::f).fmap(Applicative::coerce).coerce()); + f -> fn.apply(f).>fmap(Choice6::f) + .fmap(Applicative::coerce).coerce()); } /** @@ -229,9 +277,9 @@ private _A(A a) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn) { return aFn.apply(a); } @@ -261,9 +309,9 @@ private _B(B b) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn) { return bFn.apply(b); } @@ -293,9 +341,9 @@ private _C(C c) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn) { return cFn.apply(c); } @@ -325,9 +373,9 @@ private _D(D d) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn) { return dFn.apply(d); } @@ -357,9 +405,9 @@ private _E(E e) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn) { return eFn.apply(e); } @@ -389,9 +437,9 @@ private _F(F f) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn) { return fFn.apply(f); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java index bd7f3b65f..590796133 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java @@ -5,15 +5,17 @@ import com.jnape.palatable.lambda.adt.coproduct.CoProduct7; import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple7; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into7.into7; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** * Canonical ADT representation of {@link CoProduct7}. @@ -47,85 +49,130 @@ public Tuple7, Maybe, Maybe, Maybe, Maybe, Maybe, Maybe< return into7(HList::tuple, CoProduct7.super.project()); } + /** + * {@inheritDoc} + */ @Override public Choice8 diverge() { return match(Choice8::a, Choice8::b, Choice8::c, Choice8::d, Choice8::e, Choice8::f, Choice8::g); } + /** + * {@inheritDoc} + */ @Override - public Choice6 converge( - Function> convergenceFn) { - return match(Choice6::a, - Choice6::b, - Choice6::c, - Choice6::d, - Choice6::e, - Choice6::f, - convergenceFn.andThen(cp6 -> cp6.match(Choice6::a, Choice6::b, Choice6::c, Choice6::d, Choice6::e, Choice6::f))); + public Choice6 converge(Fn1> convergenceFn) { + return match(Choice6::a, Choice6::b, Choice6::c, Choice6::d, Choice6::e, Choice6::f, + convergenceFn.fmap(cp6 -> cp6.match(Choice6::a, Choice6::b, Choice6::c, Choice6::d, Choice6::e, + Choice6::f))); } + /** + * {@inheritDoc} + */ @Override - public Choice7 fmap(Function fn) { + public Choice7 fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override - @SuppressWarnings("unchecked") - public Choice7 biMapL(Function fn) { - return (Choice7) Bifunctor.super.biMapL(fn); + public Choice7 biMapL(Fn1 fn) { + return (Choice7) Bifunctor.super.biMapL(fn); } + /** + * {@inheritDoc} + */ @Override - @SuppressWarnings("unchecked") - public Choice7 biMapR(Function fn) { - return (Choice7) Bifunctor.super.biMapR(fn); + public Choice7 biMapR(Fn1 fn) { + return (Choice7) Bifunctor.super.biMapR(fn); } + /** + * {@inheritDoc} + */ @Override - public Choice7 biMap(Function lFn, - Function rFn) { + public Choice7 biMap(Fn1 lFn, + Fn1 rFn) { return match(Choice7::a, Choice7::b, Choice7::c, Choice7::d, Choice7::e, f -> f(lFn.apply(f)), g -> g(rFn.apply(g))); } + /** + * {@inheritDoc} + */ @Override public Choice7 pure(H h) { return g(h); } + /** + * {@inheritDoc} + */ @Override public Choice7 zip( - Applicative, Choice7> appFn) { - return appFn.>>coerce() - .match(Choice7::a, Choice7::b, Choice7::c, Choice7::d, Choice7::e, Choice7::f, this::biMapR); + Applicative, Choice7> appFn) { + return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, Choice7>> lazyAppFn) { + return match(a -> lazy(a(a)), + b -> lazy(b(b)), + c -> lazy(c(c)), + d -> lazy(d(d)), + e -> lazy(e(e)), + f -> lazy(f(f)), + g -> lazyAppFn.fmap(choiceF -> choiceF.fmap(f -> f.apply(g)).coerce())); + } + + /** + * {@inheritDoc} + */ @Override public Choice7 discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Choice7 discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Choice7 flatMap( - Function>> fn) { + Fn1>> fn) { return match(Choice7::a, Choice7::b, Choice7::c, Choice7::d, Choice7::e, Choice7::f, g -> fn.apply(g).coerce()); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") - public >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public , TravB extends Traversable>, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, + Fn1 pure) { return match(a -> pure.apply((TravB) Choice7.a(a)).coerce(), b -> pure.apply((TravB) Choice7.b(b)).coerce(), c -> pure.apply((TravB) Choice7.c(c)), d -> pure.apply((TravB) Choice7.d(d)), e -> pure.apply((TravB) Choice7.e(e)), f -> pure.apply((TravB) Choice7.f(f)), - g -> fn.apply(g).fmap(Choice7::g).fmap(Applicative::coerce).coerce()); + g -> fn.apply(g).>fmap(Choice7::g) + .fmap(Applicative::coerce).coerce()); } /** @@ -256,10 +303,10 @@ private _A(A a) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn) { return aFn.apply(a); } @@ -289,10 +336,10 @@ private _B(B b) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn) { return bFn.apply(b); } @@ -322,10 +369,10 @@ private _C(C c) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn) { return cFn.apply(c); } @@ -355,10 +402,10 @@ private _D(D d) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn) { return dFn.apply(d); } @@ -388,10 +435,10 @@ private _E(E e) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn) { return eFn.apply(e); } @@ -421,10 +468,10 @@ private _F(F f) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn) { return fFn.apply(f); } @@ -454,10 +501,10 @@ private _G(G g) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn) { return gFn.apply(g); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java index 9755c5050..cfdb71587 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java @@ -5,15 +5,17 @@ import com.jnape.palatable.lambda.adt.coproduct.CoProduct8; import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple8; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into8.into8; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** * Canonical ADT representation of {@link CoProduct8}. @@ -47,74 +49,116 @@ public Tuple8, Maybe, Maybe, Maybe, Maybe, Maybe, Maybe< return into8(HList::tuple, CoProduct8.super.project()); } + /** + * {@inheritDoc} + */ @Override public Choice7 converge( - Function> convergenceFn) { - return match(Choice7::a, - Choice7::b, - Choice7::c, - Choice7::d, - Choice7::e, - Choice7::f, - Choice7::g, - convergenceFn.andThen(cp7 -> cp7.match(Choice7::a, Choice7::b, Choice7::c, Choice7::d, Choice7::e, Choice7::f, Choice7::g))); + Fn1> convergenceFn) { + return match(Choice7::a, Choice7::b, Choice7::c, Choice7::d, Choice7::e, Choice7::f, Choice7::g, + convergenceFn.fmap(cp7 -> cp7.match(Choice7::a, Choice7::b, Choice7::c, Choice7::d, Choice7::e, + Choice7::f, Choice7::g))); } + /** + * {@inheritDoc} + */ @Override - public Choice8 fmap(Function fn) { + public Choice8 fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override - @SuppressWarnings("unchecked") - public Choice8 biMapL(Function fn) { - return (Choice8) Bifunctor.super.biMapL(fn); + public Choice8 biMapL(Fn1 fn) { + return (Choice8) Bifunctor.super.biMapL(fn); } + /** + * {@inheritDoc} + */ @Override - @SuppressWarnings("unchecked") - public Choice8 biMapR(Function fn) { - return (Choice8) Bifunctor.super.biMapR(fn); + public Choice8 biMapR(Fn1 fn) { + return (Choice8) Bifunctor.super.biMapR(fn); } + /** + * {@inheritDoc} + */ @Override - public Choice8 biMap(Function lFn, - Function rFn) { + public Choice8 biMap(Fn1 lFn, + Fn1 rFn) { return match(Choice8::a, Choice8::b, Choice8::c, Choice8::d, Choice8::e, Choice8::f, g -> g(lFn.apply(g)), h -> h(rFn.apply(h))); } + /** + * {@inheritDoc} + */ @Override public Choice8 pure(I i) { return h(i); } + /** + * {@inheritDoc} + */ @Override public Choice8 zip( - Applicative, Choice8> appFn) { - return appFn.>>coerce() - .match(Choice8::a, Choice8::b, Choice8::c, Choice8::d, Choice8::e, Choice8::f, Choice8::g, this::biMapR); + Applicative, Choice8> appFn) { + return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, Choice8>> lazyAppFn) { + return match(a -> lazy(a(a)), + b -> lazy(b(b)), + c -> lazy(c(c)), + d -> lazy(d(d)), + e -> lazy(e(e)), + f -> lazy(f(f)), + g -> lazy(g(g)), + h -> lazyAppFn.fmap(choiceF -> choiceF.fmap(f -> f.apply(h)).coerce())); + } + + /** + * {@inheritDoc} + */ @Override public Choice8 discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Choice8 discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Choice8 flatMap( - Function>> fn) { + Fn1>> fn) { return match(Choice8::a, Choice8::b, Choice8::c, Choice8::d, Choice8::e, Choice8::f, Choice8::g, h -> fn.apply(h).coerce()); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") - public >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public , TravB extends Traversable>, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, + Fn1 pure) { return match(a -> pure.apply((TravB) Choice8.a(a)).coerce(), b -> pure.apply((TravB) Choice8.b(b)).coerce(), c -> pure.apply((TravB) Choice8.c(c)), @@ -122,7 +166,8 @@ public Choice8 flatMap( e -> pure.apply((TravB) Choice8.e(e)), f -> pure.apply((TravB) Choice8.f(f)), g -> pure.apply((TravB) Choice8.g(g)), - h -> fn.apply(h).fmap(Choice8::h).fmap(Applicative::coerce).coerce()); + h -> fn.apply(h).>fmap(Choice8::h) + .fmap(Applicative::coerce).coerce()); } /** @@ -279,10 +324,10 @@ private _A(A a) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn, Function hFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn, Fn1 hFn) { return aFn.apply(a); } @@ -312,10 +357,10 @@ private _B(B b) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn, Function hFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn, Fn1 hFn) { return bFn.apply(b); } @@ -345,10 +390,10 @@ private _C(C c) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn, Function hFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn, Fn1 hFn) { return cFn.apply(c); } @@ -378,10 +423,10 @@ private _D(D d) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn, Function hFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn, Fn1 hFn) { return dFn.apply(d); } @@ -411,10 +456,10 @@ private _E(E e) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn, Function hFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn, Fn1 hFn) { return eFn.apply(e); } @@ -444,10 +489,10 @@ private _F(F f) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn, Function hFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn, Fn1 hFn) { return fFn.apply(f); } @@ -477,10 +522,10 @@ private _G(G g) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn, Function hFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn, Fn1 hFn) { return gFn.apply(g); } @@ -510,10 +555,10 @@ private _H(H h) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn, Function hFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn, Fn1 hFn) { return hFn.apply(h); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct2.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct2.java index 5ad1a9908..ecb08fece 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct2.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct2.java @@ -6,8 +6,6 @@ import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functions.Fn1; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; @@ -32,12 +30,12 @@ public interface CoProduct2> { /** * Type-safe convergence requiring a match against all potential types. * + * @param result type * @param aFn morphism A -> R * @param bFn morphism B -> R - * @param result type * @return the result of applying the appropriate morphism to this coproduct's unwrapped value */ - R match(Function aFn, Function bFn); + R match(Fn1 aFn, Fn1 bFn); /** * Diverge this coproduct by introducing another possible type that it could represent. As no morphisms can be @@ -63,8 +61,8 @@ public interface CoProduct2> { default CoProduct3> diverge() { return new CoProduct3>() { @Override - public R match(Function aFn, Function bFn, - Function cFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn) { return CoProduct2.this.match(aFn, bFn); } }; @@ -107,7 +105,7 @@ default Maybe projectB() { default CoProduct2> invert() { return new CoProduct2>() { @Override - public R match(Function aFn, Function bFn) { + public R match(Fn1 aFn, Fn1 bFn) { return CoProduct2.this.match(bFn, aFn); } }; @@ -118,14 +116,13 @@ public R match(Function aFn, Function result type * @param aFn morphism A v B -> R, applied in the A case * @param bFn morphism A v B -> R, applied in the B case - * @param result type * @return the result of applying the appropriate morphism to this coproduct */ @SuppressWarnings("unchecked") - default R embed(Function aFn, - Function bFn) { + default R embed(Fn1 aFn, Fn1 bFn) { return this.>match(constantly(fn1(aFn)), constantly(fn1(bFn))) .apply((CP2) this); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct3.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct3.java index 23a97ac9c..aee747317 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct3.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct3.java @@ -1,11 +1,10 @@ package com.jnape.palatable.lambda.adt.coproduct; import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.choice.Choice2; import com.jnape.palatable.lambda.adt.product.Product3; import com.jnape.palatable.lambda.functions.Fn1; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; @@ -27,15 +26,14 @@ public interface CoProduct3> { /** * Type-safe convergence requiring a match against all potential types. * + * @param result type * @param aFn morphism A -> R * @param bFn morphism B -> R * @param cFn morphism C -> R - * @param result type * @return the result of applying the appropriate morphism to this coproduct's unwrapped value - * @see CoProduct2#match(Function, Function) + * @see CoProduct2#match(Fn1, Fn1) */ - R match(Function aFn, Function bFn, - Function cFn); + R match(Fn1 aFn, Fn1 bFn, Fn1 cFn); /** * Diverge this coproduct by introducing another possible type that it could represent. @@ -47,8 +45,8 @@ R match(Function aFn, Function CoProduct4> diverge() { return new CoProduct4>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn) { return CoProduct3.this.match(aFn, bFn, cFn); } }; @@ -68,18 +66,8 @@ public R match(Function aFn, Function> converge( - Function> convergenceFn) { - return match(a -> new CoProduct2>() { - @Override - public R match(Function aFn, Function bFn) { - return aFn.apply(a); - } - }, b -> new CoProduct2>() { - @Override - public R match(Function aFn, Function bFn) { - return bFn.apply(b); - } - }, convergenceFn); + Fn1> convergenceFn) { + return match(Choice2::a, Choice2::b, convergenceFn::apply); } /** @@ -126,16 +114,15 @@ default Maybe projectC() { * the appropriate morphism to this coproduct as a whole. Like {@link CoProduct3#match}, but without unwrapping the * value. * + * @param result type * @param aFn morphism A v B v C -> R, applied in the A case * @param bFn morphism A v B v C -> R, applied in the B case * @param cFn morphism A v B v C -> R, applied in the C case - * @param result type * @return the result of applying the appropriate morphism to this coproduct */ @SuppressWarnings("unchecked") - default R embed(Function aFn, - Function bFn, - Function cFn) { + default R embed(Fn1 aFn, Fn1 bFn, + Fn1 cFn) { return this.>match(constantly(fn1(aFn)), constantly(fn1(bFn)), constantly(fn1(cFn))) diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4.java index 2ec2e113d..4deea96eb 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4.java @@ -1,11 +1,10 @@ package com.jnape.palatable.lambda.adt.coproduct; import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.choice.Choice3; import com.jnape.palatable.lambda.adt.product.Product4; import com.jnape.palatable.lambda.functions.Fn1; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; @@ -28,18 +27,18 @@ public interface CoProduct4> { /** * Type-safe convergence requiring a match against all potential types. * + * @param result type * @param aFn morphism A -> R * @param bFn morphism B -> R * @param cFn morphism C -> R * @param dFn morphism D -> R - * @param result type * @return the result of applying the appropriate morphism from whichever type is represented by this coproduct to R - * @see CoProduct2#match(Function, Function) + * @see CoProduct2#match(Fn1, Fn1) */ - R match(Function aFn, - Function bFn, - Function cFn, - Function dFn); + R match(Fn1 aFn, + Fn1 bFn, + Fn1 cFn, + Fn1 dFn); /** * Diverge this coproduct by introducing another possible type that it could represent. @@ -51,9 +50,9 @@ R match(Function aFn, default CoProduct5> diverge() { return new CoProduct5>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn) { return CoProduct4.this.match(aFn, bFn, cFn, dFn); } }; @@ -68,26 +67,8 @@ public R match(Function aFn, Function> converge( - Function> convergenceFn) { - return match(a -> new CoProduct3>() { - @Override - public R match(Function aFn, Function bFn, - Function cFn) { - return aFn.apply(a); - } - }, b -> new CoProduct3>() { - @Override - public R match(Function aFn, Function bFn, - Function cFn) { - return bFn.apply(b); - } - }, c -> new CoProduct3>() { - @Override - public R match(Function aFn, Function bFn, - Function cFn) { - return cFn.apply(c); - } - }, convergenceFn); + Fn1> convergenceFn) { + return match(Choice3::a, Choice3::b, Choice3::c, convergenceFn::apply); } /** @@ -144,18 +125,18 @@ default Maybe projectD() { * the appropriate morphism to this coproduct as a whole. Like {@link CoProduct4#match}, but without unwrapping the * value. * + * @param result type * @param aFn morphism A v B v C v D -> R, applied in the A case * @param bFn morphism A v B v C v D -> R, applied in the B case * @param cFn morphism A v B v C v D -> R, applied in the C case * @param dFn morphism A v B v C v D -> R, applied in the D case - * @param result type * @return the result of applying the appropriate morphism to this coproduct */ @SuppressWarnings("unchecked") - default R embed(Function aFn, - Function bFn, - Function cFn, - Function dFn) { + default R embed(Fn1 aFn, + Fn1 bFn, + Fn1 cFn, + Fn1 dFn) { return this.>match(constantly(fn1(aFn)), constantly(fn1(bFn)), constantly(fn1(cFn)), diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct5.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct5.java index b90aab2f5..03b594ca2 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct5.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct5.java @@ -1,11 +1,10 @@ package com.jnape.palatable.lambda.adt.coproduct; import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.choice.Choice4; import com.jnape.palatable.lambda.adt.product.Product5; import com.jnape.palatable.lambda.functions.Fn1; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; @@ -29,20 +28,20 @@ public interface CoProduct5 result type * @param aFn morphism A -> R * @param bFn morphism B -> R * @param cFn morphism C -> R * @param dFn morphism D -> R * @param eFn morphism E -> R - * @param result type * @return the result of applying the appropriate morphism from whichever type is represented by this coproduct to R - * @see CoProduct2#match(Function, Function) + * @see CoProduct2#match(Fn1, Fn1) */ - R match(Function aFn, - Function bFn, - Function cFn, - Function dFn, - Function eFn); + R match(Fn1 aFn, + Fn1 bFn, + Fn1 cFn, + Fn1 dFn, + Fn1 eFn); /** * Diverge this coproduct by introducing another possible type that it could represent. @@ -54,9 +53,9 @@ R match(Function aFn, default CoProduct6> diverge() { return new CoProduct6>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn) { return CoProduct5.this.match(aFn, bFn, cFn, dFn, eFn); } }; @@ -70,32 +69,8 @@ public R match(Function aFn, Function> converge( - Function> convergenceFn) { - return match(a -> new CoProduct4>() { - @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn) { - return aFn.apply(a); - } - }, b -> new CoProduct4>() { - @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn) { - return bFn.apply(b); - } - }, c -> new CoProduct4>() { - @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn) { - return cFn.apply(c); - } - }, d -> new CoProduct4>() { - @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn) { - return dFn.apply(d); - } - }, convergenceFn::apply); + Fn1> convergenceFn) { + return match(Choice4::a, Choice4::b, Choice4::c, Choice4::d, convergenceFn::apply); } /** @@ -162,20 +137,20 @@ default Maybe projectE() { * the appropriate morphism to this coproduct as a whole. Like {@link CoProduct5#match}, but without unwrapping the * value. * + * @param result type * @param aFn morphism A v B v C v D v E -> R, applied in the A case * @param bFn morphism A v B v C v D v E -> R, applied in the B case * @param cFn morphism A v B v C v D v E -> R, applied in the C case * @param dFn morphism A v B v C v D v E -> R, applied in the D case * @param eFn morphism A v B v C v D v E -> R, applied in the E case - * @param result type * @return the result of applying the appropriate morphism to this coproduct */ @SuppressWarnings("unchecked") - default R embed(Function aFn, - Function bFn, - Function cFn, - Function dFn, - Function eFn) { + default R embed(Fn1 aFn, + Fn1 bFn, + Fn1 cFn, + Fn1 dFn, + Fn1 eFn) { return this.>match(constantly(fn1(aFn)), constantly(fn1(bFn)), constantly(fn1(cFn)), diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct6.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct6.java index a3aa40163..d8d8d2301 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct6.java @@ -5,8 +5,6 @@ import com.jnape.palatable.lambda.adt.product.Product6; import com.jnape.palatable.lambda.functions.Fn1; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; @@ -31,22 +29,22 @@ public interface CoProduct6 result type * @param aFn morphism A -> R * @param bFn morphism B -> R * @param cFn morphism C -> R * @param dFn morphism D -> R * @param eFn morphism E -> R * @param fFn morphism F -> R - * @param result type * @return the result of applying the appropriate morphism from whichever type is represented by this coproduct to R - * @see CoProduct2#match(Function, Function) + * @see CoProduct2#match(Fn1, Fn1) */ - R match(Function aFn, - Function bFn, - Function cFn, - Function dFn, - Function eFn, - Function fFn); + R match(Fn1 aFn, + Fn1 bFn, + Fn1 cFn, + Fn1 dFn, + Fn1 eFn, + Fn1 fFn); /** * Diverge this coproduct by introducing another possible type that it could represent. @@ -58,10 +56,10 @@ R match(Function aFn, default CoProduct7> diverge() { return new CoProduct7>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn) { return CoProduct6.this.match(aFn, bFn, cFn, dFn, eFn, fFn); } }; @@ -75,7 +73,7 @@ public R match(Function aFn, Function> converge( - Function> convergenceFn) { + Fn1> convergenceFn) { return match(Choice5::a, Choice5::b, Choice5::c, Choice5::d, Choice5::e, convergenceFn::apply); } @@ -153,22 +151,22 @@ default Maybe projectF() { * the appropriate morphism to this coproduct as a whole. Like {@link CoProduct6#match}, but without unwrapping the * value. * + * @param result type * @param aFn morphism A v B v C v D v E v F -> R, applied in the A case * @param bFn morphism A v B v C v D v E v F -> R, applied in the B case * @param cFn morphism A v B v C v D v E v F -> R, applied in the C case * @param dFn morphism A v B v C v D v E v F -> R, applied in the D case * @param eFn morphism A v B v C v D v E v F -> R, applied in the E case * @param fFn morphism A v B v C v D v E v F -> R, applied in the F case - * @param result type * @return the result of applying the appropriate morphism to this coproduct */ @SuppressWarnings("unchecked") - default R embed(Function aFn, - Function bFn, - Function cFn, - Function dFn, - Function eFn, - Function fFn) { + default R embed(Fn1 aFn, + Fn1 bFn, + Fn1 cFn, + Fn1 dFn, + Fn1 eFn, + Fn1 fFn) { return this.>match(constantly(fn1(aFn)), constantly(fn1(bFn)), constantly(fn1(cFn)), diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct7.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct7.java index 18086211c..0f7647f96 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct7.java @@ -5,8 +5,6 @@ import com.jnape.palatable.lambda.adt.product.Product7; import com.jnape.palatable.lambda.functions.Fn1; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; @@ -32,6 +30,7 @@ public interface CoProduct7 result type * @param aFn morphism A -> R * @param bFn morphism B -> R * @param cFn morphism C -> R @@ -39,17 +38,16 @@ public interface CoProduct7E -> R * @param fFn morphism F -> R * @param gFn morphism G -> R - * @param result type * @return the result of applying the appropriate morphism from whichever type is represented by this coproduct to R - * @see CoProduct2#match(Function, Function) + * @see CoProduct2#match(Fn1, Fn1) */ - R match(Function aFn, - Function bFn, - Function cFn, - Function dFn, - Function eFn, - Function fFn, - Function gFn); + R match(Fn1 aFn, + Fn1 bFn, + Fn1 cFn, + Fn1 dFn, + Fn1 eFn, + Fn1 fFn, + Fn1 gFn); /** * Diverge this coproduct by introducing another possible type that it could represent. @@ -61,10 +59,10 @@ R match(Function aFn, default CoProduct8> diverge() { return new CoProduct8>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn, Function hFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn, Fn1 hFn) { return CoProduct7.this.match(aFn, bFn, cFn, dFn, eFn, fFn, gFn); } }; @@ -78,7 +76,7 @@ public R match(Function aFn, Function> converge( - Function> convergenceFn) { + Fn1> convergenceFn) { return match(Choice6::a, Choice6::b, Choice6::c, Choice6::d, Choice6::e, Choice6::f, convergenceFn::apply); } @@ -166,6 +164,7 @@ default Maybe projectG() { * the appropriate morphism to this coproduct as a whole. Like {@link CoProduct7#match}, but without unwrapping the * value. * + * @param result type * @param aFn morphism A v B v C v D v E v F v G -> R, applied in the A case * @param bFn morphism A v B v C v D v E v F v G -> R, applied in the B case * @param cFn morphism A v B v C v D v E v F v G -> R, applied in the C case @@ -173,17 +172,16 @@ default Maybe projectG() { * @param eFn morphism A v B v C v D v E v F v G -> R, applied in the E case * @param fFn morphism A v B v C v D v E v F v G -> R, applied in the F case * @param gFn morphism A v B v C v D v E v F v G -> R, applied in the G case - * @param result type * @return the result of applying the appropriate morphism to this coproduct */ @SuppressWarnings("unchecked") - default R embed(Function aFn, - Function bFn, - Function cFn, - Function dFn, - Function eFn, - Function fFn, - Function gFn) { + default R embed(Fn1 aFn, + Fn1 bFn, + Fn1 cFn, + Fn1 dFn, + Fn1 eFn, + Fn1 fFn, + Fn1 gFn) { return this.>match(constantly(fn1(aFn)), constantly(fn1(bFn)), constantly(fn1(cFn)), diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct8.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct8.java index 776f067e8..9653e178a 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct8.java @@ -5,8 +5,6 @@ import com.jnape.palatable.lambda.adt.product.Product8; import com.jnape.palatable.lambda.functions.Fn1; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; @@ -33,6 +31,7 @@ public interface CoProduct8 result type * @param aFn morphism A -> R * @param bFn morphism B -> R * @param cFn morphism C -> R @@ -41,18 +40,17 @@ public interface CoProduct8F -> R * @param gFn morphism G -> R * @param hFn morphism H -> R - * @param result type * @return the result of applying the appropriate morphism from whichever type is represented by this coproduct to R - * @see CoProduct2#match(Function, Function) + * @see CoProduct2#match(Fn1, Fn1) */ - R match(Function aFn, - Function bFn, - Function cFn, - Function dFn, - Function eFn, - Function fFn, - Function gFn, - Function hFn); + R match(Fn1 aFn, + Fn1 bFn, + Fn1 cFn, + Fn1 dFn, + Fn1 eFn, + Fn1 fFn, + Fn1 gFn, + Fn1 hFn); /** * Converge this coproduct down to a lower order coproduct by mapping the last possible type into an earlier @@ -62,8 +60,9 @@ R match(Function aFn, * @return a {@link CoProduct7}<A, B, C, D, E, F, G> */ default CoProduct7> converge( - Function> convergenceFn) { - return match(Choice7::a, Choice7::b, Choice7::c, Choice7::d, Choice7::e, Choice7::f, Choice7::g, convergenceFn::apply); + Fn1> convergenceFn) { + return match(Choice7::a, Choice7::b, Choice7::c, Choice7::d, Choice7::e, Choice7::f, Choice7::g, + convergenceFn::apply); } /** @@ -160,6 +159,7 @@ default Maybe projectH() { * the appropriate morphism to this coproduct as a whole. Like {@link CoProduct8#match}, but without unwrapping the * value. * + * @param result type * @param aFn morphism A v B v C v D v E v F v G v H -> R, applied in the A case * @param bFn morphism A v B v C v D v E v F v G v H -> R, applied in the B case * @param cFn morphism A v B v C v D v E v F v G v H -> R, applied in the C case @@ -168,18 +168,17 @@ default Maybe projectH() { * @param fFn morphism A v B v C v D v E v F v G v H -> R, applied in the F case * @param gFn morphism A v B v C v D v E v F v G v H -> R, applied in the G case * @param hFn morphism A v B v C v D v E v F v G v H -> R, applied in the H case - * @param result type * @return the result of applying the appropriate morphism to this coproduct */ @SuppressWarnings("unchecked") - default R embed(Function aFn, - Function bFn, - Function cFn, - Function dFn, - Function eFn, - Function fFn, - Function gFn, - Function hFn) { + default R embed(Fn1 aFn, + Fn1 bFn, + Fn1 cFn, + Fn1 dFn, + Fn1 eFn, + Fn1 fFn, + Fn1 gFn, + Fn1 hFn) { return this.>match(constantly(fn1(aFn)), constantly(fn1(bFn)), constantly(fn1(cFn)), diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/HList.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/HList.java index bfb0b8f79..91f19edbe 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/HList.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/HList.java @@ -34,7 +34,7 @@ public final String toString() { HList next = this; while (next != HNil.INSTANCE) { - HCons hCons = (HCons) next; + HCons hCons = (HCons) next; body.append(" ").append(hCons.head).append(" "); next = hCons.tail; if (next != HNil.INSTANCE) @@ -269,7 +269,7 @@ public Tail tail() { @Override public final boolean equals(Object other) { if (other instanceof HCons) { - HCons that = (HCons) other; + HCons that = (HCons) other; return this.head.equals(that.head) && this.tail.equals(that.tail); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Index.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Index.java index 12f1eeebd..6a59384c6 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Index.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Index.java @@ -55,7 +55,7 @@ private Index() { private static final class Z extends Index> { - private static final Z INSTANCE = new Z(); + private static final Z INSTANCE = new Z<>(); @Override public Target get(HCons hList) { diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java index 0a8143d84..176745aba 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java @@ -2,12 +2,12 @@ import com.jnape.palatable.lambda.adt.hlist.HList.HCons; import com.jnape.palatable.lambda.adt.hlist.HList.HNil; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; -import java.util.function.Function; - /** * A singleton HList. Supports random access. * @@ -18,7 +18,9 @@ * @see Tuple4 * @see Tuple5 */ -public class SingletonHList<_1> extends HCons<_1, HNil> implements Monad<_1, SingletonHList>, Traversable<_1, SingletonHList> { +public class SingletonHList<_1> extends HCons<_1, HNil> implements + Monad<_1, SingletonHList>, + Traversable<_1, SingletonHList> { SingletonHList(_1 _1) { super(_1, nil()); @@ -30,7 +32,7 @@ public <_0> Tuple2<_0, _1> cons(_0 _0) { } @Override - public <_1Prime> SingletonHList<_1Prime> fmap(Function fn) { + public <_1Prime> SingletonHList<_1Prime> fmap(Fn1 fn) { return Monad.super.<_1Prime>fmap(fn).coerce(); } @@ -41,40 +43,46 @@ public <_1Prime> SingletonHList<_1Prime> pure(_1Prime _1Prime) { @Override public <_1Prime> SingletonHList<_1Prime> zip( - Applicative, SingletonHList> appFn) { + Applicative, SingletonHList> appFn) { return Monad.super.zip(appFn).coerce(); } @Override - public <_1Prime> SingletonHList<_1Prime> discardL(Applicative<_1Prime, SingletonHList> appB) { + public <_1Prime> Lazy> lazyZip( + Lazy, SingletonHList>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_1Prime, SingletonHList>::coerce); + } + + @Override + public <_1Prime> SingletonHList<_1Prime> discardL(Applicative<_1Prime, SingletonHList> appB) { return Monad.super.discardL(appB).coerce(); } @Override - public <_1Prime> SingletonHList<_1> discardR(Applicative<_1Prime, SingletonHList> appB) { + public <_1Prime> SingletonHList<_1> discardR(Applicative<_1Prime, SingletonHList> appB) { return Monad.super.discardR(appB).coerce(); } @Override - public <_1Prime> SingletonHList<_1Prime> flatMap(Function> f) { + public <_1Prime> SingletonHList<_1Prime> flatMap(Fn1>> f) { return f.apply(head()).coerce(); } @Override - @SuppressWarnings("unchecked") - public , AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public , TravB extends Traversable>, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, + Fn1 pure) { return fn.apply(head()).fmap(SingletonHList::new).fmap(Applicative::coerce).coerce(); } /** - * Apply {@link SingletonHList#head} to fn and return the result. + * Apply {@link SingletonHList#head()} to fn and return the result. * * @param fn the function to apply * @param the return type of the function * @return the result of applying the head to the function */ - public R into(Function fn) { + public R into(Fn1 fn) { return fn.apply(head()); } } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple2.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple2.java index 621537198..78bf332c3 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple2.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple2.java @@ -2,13 +2,14 @@ import com.jnape.palatable.lambda.adt.hlist.HList.HCons; import com.jnape.palatable.lambda.adt.product.Product2; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Map; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; @@ -28,7 +29,7 @@ public class Tuple2<_1, _2> extends HCons<_1, SingletonHList<_2>> implements Product2<_1, _2>, Map.Entry<_1, _2>, Monad<_2, Tuple2<_1, ?>>, - Bifunctor<_1, _2, Tuple2>, + Bifunctor<_1, _2, Tuple2>, Traversable<_2, Tuple2<_1, ?>> { private final _1 _1; @@ -76,25 +77,25 @@ public Tuple2<_2, _1> invert() { } @Override - public <_2Prime> Tuple2<_1, _2Prime> fmap(Function fn) { + public <_2Prime> Tuple2<_1, _2Prime> fmap(Fn1 fn) { return Monad.super.<_2Prime>fmap(fn).coerce(); } @Override @SuppressWarnings("unchecked") - public <_1Prime> Tuple2<_1Prime, _2> biMapL(Function fn) { + public <_1Prime> Tuple2<_1Prime, _2> biMapL(Fn1 fn) { return (Tuple2<_1Prime, _2>) Bifunctor.super.biMapL(fn); } @Override @SuppressWarnings("unchecked") - public <_2Prime> Tuple2<_1, _2Prime> biMapR(Function fn) { + public <_2Prime> Tuple2<_1, _2Prime> biMapR(Fn1 fn) { return (Tuple2<_1, _2Prime>) Bifunctor.super.biMapR(fn); } @Override - public <_1Prime, _2Prime> Tuple2<_1Prime, _2Prime> biMap(Function lFn, - Function rFn) { + public <_1Prime, _2Prime> Tuple2<_1Prime, _2Prime> biMap(Fn1 lFn, + Fn1 rFn) { return new Tuple2<>(lFn.apply(_1()), tail().fmap(rFn)); } @@ -105,10 +106,16 @@ public <_2Prime> Tuple2<_1, _2Prime> pure(_2Prime _2Prime) { @Override public <_2Prime> Tuple2<_1, _2Prime> zip( - Applicative, Tuple2<_1, ?>> appFn) { + Applicative, Tuple2<_1, ?>> appFn) { return Monad.super.zip(appFn).coerce(); } + @Override + public <_2Prime> Lazy> lazyZip( + Lazy, Tuple2<_1, ?>>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_2Prime, Tuple2<_1, ?>>::coerce); + } + @Override public <_2Prime> Tuple2<_1, _2Prime> discardL(Applicative<_2Prime, Tuple2<_1, ?>> appB) { return Monad.super.discardL(appB).coerce(); @@ -120,14 +127,15 @@ public <_2Prime> Tuple2<_1, _2> discardR(Applicative<_2Prime, Tuple2<_1, ?>> app } @Override - public <_2Prime> Tuple2<_1, _2Prime> flatMap(Function>> f) { + public <_2Prime> Tuple2<_1, _2Prime> flatMap(Fn1>> f) { return pure(f.apply(_2).>coerce()._2()); } @Override - @SuppressWarnings("unchecked") - public <_2Prime, App extends Applicative, TravB extends Traversable<_2Prime, Tuple2<_1, ?>>, AppB extends Applicative<_2Prime, App>, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public <_2Prime, App extends Applicative, TravB extends Traversable<_2Prime, Tuple2<_1, ?>>, + AppTrav extends Applicative> AppTrav traverse( + Fn1> fn, + Fn1 pure) { return fn.apply(_2).fmap(_2Prime -> fmap(constantly(_2Prime))).fmap(Applicative::coerce).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple3.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple3.java index 32d8a5359..0e99a88b9 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple3.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple3.java @@ -2,13 +2,13 @@ import com.jnape.palatable.lambda.adt.hlist.HList.HCons; import com.jnape.palatable.lambda.adt.product.Product3; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; /** @@ -78,25 +78,25 @@ public Tuple3<_2, _1, _3> invert() { @Override @SuppressWarnings("unchecked") - public <_3Prime> Tuple3<_1, _2, _3Prime> fmap(Function fn) { + public <_3Prime> Tuple3<_1, _2, _3Prime> fmap(Fn1 fn) { return (Tuple3<_1, _2, _3Prime>) Monad.super.fmap(fn); } @Override @SuppressWarnings("unchecked") - public <_2Prime> Tuple3<_1, _2Prime, _3> biMapL(Function fn) { + public <_2Prime> Tuple3<_1, _2Prime, _3> biMapL(Fn1 fn) { return (Tuple3<_1, _2Prime, _3>) Bifunctor.super.biMapL(fn); } @Override @SuppressWarnings("unchecked") - public <_3Prime> Tuple3<_1, _2, _3Prime> biMapR(Function fn) { + public <_3Prime> Tuple3<_1, _2, _3Prime> biMapR(Fn1 fn) { return (Tuple3<_1, _2, _3Prime>) Bifunctor.super.biMapR(fn); } @Override - public <_2Prime, _3Prime> Tuple3<_1, _2Prime, _3Prime> biMap(Function lFn, - Function rFn) { + public <_2Prime, _3Prime> Tuple3<_1, _2Prime, _3Prime> biMap(Fn1 lFn, + Fn1 rFn) { return new Tuple3<>(_1(), tail().biMap(lFn, rFn)); } @@ -107,8 +107,14 @@ public <_3Prime> Tuple3<_1, _2, _3Prime> pure(_3Prime _3Prime) { @Override public <_3Prime> Tuple3<_1, _2, _3Prime> zip( - Applicative, Tuple3<_1, _2, ?>> appFn) { - return biMapR(appFn.>>coerce()._3()); + Applicative, Tuple3<_1, _2, ?>> appFn) { + return biMapR(appFn.>>coerce()._3()::apply); + } + + @Override + public <_3Prime> Lazy> lazyZip( + Lazy, Tuple3<_1, _2, ?>>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_3Prime, Tuple3<_1, _2, ?>>::coerce); } @Override @@ -123,14 +129,15 @@ public <_3Prime> Tuple3<_1, _2, _3> discardR(Applicative<_3Prime, Tuple3<_1, _2, @Override public <_3Prime> Tuple3<_1, _2, _3Prime> flatMap( - Function>> f) { + Fn1>> f) { return pure(f.apply(_3).>coerce()._3); } @Override - @SuppressWarnings("unchecked") - public <_3Prime, App extends Applicative, TravB extends Traversable<_3Prime, Tuple3<_1, _2, ?>>, AppB extends Applicative<_3Prime, App>, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public <_3Prime, App extends Applicative, TravB extends Traversable<_3Prime, Tuple3<_1, _2, ?>>, + AppTrav extends Applicative> AppTrav traverse( + Fn1> fn, + Fn1 pure) { return fn.apply(_3).fmap(_3Prime -> fmap(constantly(_3Prime))).fmap(Applicative::coerce).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple4.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple4.java index af141c9f3..1e99d3fd5 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple4.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple4.java @@ -2,13 +2,13 @@ import com.jnape.palatable.lambda.adt.hlist.HList.HCons; import com.jnape.palatable.lambda.adt.product.Product4; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; /** @@ -95,23 +95,23 @@ public Tuple4<_2, _1, _3, _4> invert() { } @Override - public <_4Prime> Tuple4<_1, _2, _3, _4Prime> fmap(Function fn) { + public <_4Prime> Tuple4<_1, _2, _3, _4Prime> fmap(Fn1 fn) { return (Tuple4<_1, _2, _3, _4Prime>) Monad.super.<_4Prime>fmap(fn); } @Override - public <_3Prime> Tuple4<_1, _2, _3Prime, _4> biMapL(Function fn) { + public <_3Prime> Tuple4<_1, _2, _3Prime, _4> biMapL(Fn1 fn) { return (Tuple4<_1, _2, _3Prime, _4>) Bifunctor.super.<_3Prime>biMapL(fn); } @Override - public <_4Prime> Tuple4<_1, _2, _3, _4Prime> biMapR(Function fn) { + public <_4Prime> Tuple4<_1, _2, _3, _4Prime> biMapR(Fn1 fn) { return (Tuple4<_1, _2, _3, _4Prime>) Bifunctor.super.<_4Prime>biMapR(fn); } @Override - public <_3Prime, _4Prime> Tuple4<_1, _2, _3Prime, _4Prime> biMap(Function lFn, - Function rFn) { + public <_3Prime, _4Prime> Tuple4<_1, _2, _3Prime, _4Prime> biMap(Fn1 lFn, + Fn1 rFn) { return new Tuple4<>(_1(), tail().biMap(lFn, rFn)); } @@ -122,8 +122,14 @@ public <_4Prime> Tuple4<_1, _2, _3, _4Prime> pure(_4Prime _4Prime) { @Override public <_4Prime> Tuple4<_1, _2, _3, _4Prime> zip( - Applicative, Tuple4<_1, _2, _3, ?>> appFn) { - return biMapR(appFn.>>coerce()._4()); + Applicative, Tuple4<_1, _2, _3, ?>> appFn) { + return biMapR(appFn.>>coerce()._4()::apply); + } + + @Override + public <_4Prime> Lazy> lazyZip( + Lazy, Tuple4<_1, _2, _3, ?>>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_4Prime, Tuple4<_1, _2, _3, ?>>::coerce); } @Override @@ -138,14 +144,15 @@ public <_4Prime> Tuple4<_1, _2, _3, _4> discardR(Applicative<_4Prime, Tuple4<_1, @Override public <_4Prime> Tuple4<_1, _2, _3, _4Prime> flatMap( - Function>> f) { + Fn1>> f) { return pure(f.apply(_4).>coerce()._4); } @Override - @SuppressWarnings("unchecked") - public <_4Prime, App extends Applicative, TravB extends Traversable<_4Prime, Tuple4<_1, _2, _3, ?>>, AppB extends Applicative<_4Prime, App>, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public <_4Prime, App extends Applicative, TravB extends Traversable<_4Prime, Tuple4<_1, _2, _3, ?>>, + AppTrav extends Applicative> AppTrav traverse( + Fn1> fn, + Fn1 pure) { return fn.apply(_4).fmap(_4Prime -> fmap(constantly(_4Prime))).fmap(Applicative::coerce).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple5.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple5.java index 65dfb3c7a..0292831d2 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple5.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple5.java @@ -2,13 +2,13 @@ import com.jnape.palatable.lambda.adt.hlist.HList.HCons; import com.jnape.palatable.lambda.adt.product.Product5; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; /** @@ -113,25 +113,25 @@ public Tuple5<_2, _1, _3, _4, _5> invert() { } @Override - public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> fmap(Function fn) { + public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> fmap(Fn1 fn) { return Monad.super.<_5Prime>fmap(fn).coerce(); } @Override @SuppressWarnings("unchecked") - public <_4Prime> Tuple5<_1, _2, _3, _4Prime, _5> biMapL(Function fn) { + public <_4Prime> Tuple5<_1, _2, _3, _4Prime, _5> biMapL(Fn1 fn) { return (Tuple5<_1, _2, _3, _4Prime, _5>) Bifunctor.super.biMapL(fn); } @Override @SuppressWarnings("unchecked") - public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> biMapR(Function fn) { + public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> biMapR(Fn1 fn) { return (Tuple5<_1, _2, _3, _4, _5Prime>) Bifunctor.super.biMapR(fn); } @Override - public <_4Prime, _5Prime> Tuple5<_1, _2, _3, _4Prime, _5Prime> biMap(Function lFn, - Function rFn) { + public <_4Prime, _5Prime> Tuple5<_1, _2, _3, _4Prime, _5Prime> biMap(Fn1 lFn, + Fn1 rFn) { return new Tuple5<>(_1(), tail().biMap(lFn, rFn)); } @@ -142,10 +142,16 @@ public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> pure(_5Prime _5Prime) { @Override public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> zip( - Applicative, Tuple5<_1, _2, _3, _4, ?>> appFn) { + Applicative, Tuple5<_1, _2, _3, _4, ?>> appFn) { return Monad.super.zip(appFn).coerce(); } + @Override + public <_5Prime> Lazy> lazyZip( + Lazy, Tuple5<_1, _2, _3, _4, ?>>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_5Prime, Tuple5<_1, _2, _3, _4, ?>>::coerce); + } + @Override public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> discardL(Applicative<_5Prime, Tuple5<_1, _2, _3, _4, ?>> appB) { return Monad.super.discardL(appB).coerce(); @@ -158,14 +164,15 @@ public <_5Prime> Tuple5<_1, _2, _3, _4, _5> discardR(Applicative<_5Prime, Tuple5 @Override public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> flatMap( - Function>> f) { + Fn1>> f) { return pure(f.apply(_5).>coerce()._5()); } @Override - @SuppressWarnings("unchecked") - public <_5Prime, App extends Applicative, TravB extends Traversable<_5Prime, Tuple5<_1, _2, _3, _4, ?>>, AppB extends Applicative<_5Prime, App>, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public <_5Prime, App extends Applicative, TravB extends Traversable<_5Prime, Tuple5<_1, _2, _3, _4, ?>>, + AppTrav extends Applicative> AppTrav traverse( + Fn1> fn, + Fn1 pure) { return fn.apply(_5).fmap(_3Prime -> fmap(constantly(_3Prime))).fmap(Applicative::coerce).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java index 0f3046ace..86991a8ae 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java @@ -2,13 +2,13 @@ import com.jnape.palatable.lambda.adt.hlist.HList.HCons; import com.jnape.palatable.lambda.adt.product.Product6; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; /** @@ -132,26 +132,26 @@ public Tuple6<_2, _1, _3, _4, _5, _6> invert() { } @Override - public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> fmap(Function fn) { + public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> fmap(Fn1 fn) { return Monad.super.<_6Prime>fmap(fn).coerce(); } @Override @SuppressWarnings("unchecked") - public <_5Prime> Tuple6<_1, _2, _3, _4, _5Prime, _6> biMapL(Function fn) { + public <_5Prime> Tuple6<_1, _2, _3, _4, _5Prime, _6> biMapL(Fn1 fn) { return (Tuple6<_1, _2, _3, _4, _5Prime, _6>) Bifunctor.super.biMapL(fn); } @Override @SuppressWarnings("unchecked") - public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> biMapR(Function fn) { + public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> biMapR(Fn1 fn) { return (Tuple6<_1, _2, _3, _4, _5, _6Prime>) Bifunctor.super.biMapR(fn); } @Override public <_5Prime, _6Prime> Tuple6<_1, _2, _3, _4, _5Prime, _6Prime> biMap( - Function lFn, - Function rFn) { + Fn1 lFn, + Fn1 rFn) { return new Tuple6<>(_1(), tail().biMap(lFn, rFn)); } @@ -162,10 +162,16 @@ public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> pure(_6Prime _6Prime) { @Override public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> zip( - Applicative, Tuple6<_1, _2, _3, _4, _5, ?>> appFn) { + Applicative, Tuple6<_1, _2, _3, _4, _5, ?>> appFn) { return Monad.super.zip(appFn).coerce(); } + @Override + public <_6Prime> Lazy> lazyZip( + Lazy, Tuple6<_1, _2, _3, _4, _5, ?>>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_6Prime, Tuple6<_1, _2, _3, _4, _5, ?>>::coerce); + } + @Override public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> discardL( Applicative<_6Prime, Tuple6<_1, _2, _3, _4, _5, ?>> appB) { @@ -179,14 +185,15 @@ public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6> discardR(Applicative<_6Prime, Tu @Override public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> flatMap( - Function>> f) { + Fn1>> f) { return pure(f.apply(_6).>coerce()._6()); } @Override - @SuppressWarnings("unchecked") - public <_6Prime, App extends Applicative, TravB extends Traversable<_6Prime, Tuple6<_1, _2, _3, _4, _5, ?>>, AppB extends Applicative<_6Prime, App>, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public <_6Prime, App extends Applicative, TravB extends Traversable<_6Prime, Tuple6<_1, _2, _3, _4, _5, ?>>, + AppTrav extends Applicative> AppTrav traverse( + Fn1> fn, + Fn1 pure) { return fn.apply(_6).fmap(_6Prime -> fmap(constantly(_6Prime))).fmap(Applicative::coerce).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java index 1910381d1..60d42664c 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java @@ -2,13 +2,13 @@ import com.jnape.palatable.lambda.adt.hlist.HList.HCons; import com.jnape.palatable.lambda.adt.product.Product7; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; /** @@ -151,26 +151,26 @@ public Tuple7<_2, _1, _3, _4, _5, _6, _7> invert() { } @Override - public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> fmap(Function fn) { + public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> fmap(Fn1 fn) { return Monad.super.<_7Prime>fmap(fn).coerce(); } @Override @SuppressWarnings("unchecked") - public <_6Prime> Tuple7<_1, _2, _3, _4, _5, _6Prime, _7> biMapL(Function fn) { + public <_6Prime> Tuple7<_1, _2, _3, _4, _5, _6Prime, _7> biMapL(Fn1 fn) { return (Tuple7<_1, _2, _3, _4, _5, _6Prime, _7>) Bifunctor.super.biMapL(fn); } @Override @SuppressWarnings("unchecked") - public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> biMapR(Function fn) { + public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> biMapR(Fn1 fn) { return (Tuple7<_1, _2, _3, _4, _5, _6, _7Prime>) Bifunctor.super.biMapR(fn); } @Override public <_6Prime, _7Prime> Tuple7<_1, _2, _3, _4, _5, _6Prime, _7Prime> biMap( - Function lFn, - Function rFn) { + Fn1 lFn, + Fn1 rFn) { return new Tuple7<>(_1(), tail().biMap(lFn, rFn)); } @@ -181,10 +181,16 @@ public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> pure(_7Prime _7Prime) { @Override public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> zip( - Applicative, Tuple7<_1, _2, _3, _4, _5, _6, ?>> appFn) { + Applicative, Tuple7<_1, _2, _3, _4, _5, _6, ?>> appFn) { return Monad.super.zip(appFn).coerce(); } + @Override + public <_7Prime> Lazy> lazyZip( + Lazy, Tuple7<_1, _2, _3, _4, _5, _6, ?>>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_7Prime, Tuple7<_1, _2, _3, _4, _5, _6, ?>>::coerce); + } + @Override public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> discardL( Applicative<_7Prime, Tuple7<_1, _2, _3, _4, _5, _6, ?>> appB) { @@ -199,14 +205,16 @@ public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7> discardR( @Override public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> flatMap( - Function>> f) { + Fn1>> f) { return pure(f.apply(_7).>coerce()._7()); } @Override - @SuppressWarnings("unchecked") - public <_7Prime, App extends Applicative, TravB extends Traversable<_7Prime, Tuple7<_1, _2, _3, _4, _5, _6, ?>>, AppB extends Applicative<_7Prime, App>, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public <_7Prime, App extends Applicative, + TravB extends Traversable<_7Prime, Tuple7<_1, _2, _3, _4, _5, _6, ?>>, + AppTrav extends Applicative> AppTrav traverse( + Fn1> fn, + Fn1 pure) { return fn.apply(_7).fmap(_7Prime -> fmap(constantly(_7Prime))).fmap(Applicative::coerce).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java index 30a9eba61..81054635e 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java @@ -2,13 +2,13 @@ import com.jnape.palatable.lambda.adt.hlist.HList.HCons; import com.jnape.palatable.lambda.adt.product.Product8; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; /** @@ -170,26 +170,26 @@ public Tuple8<_2, _1, _3, _4, _5, _6, _7, _8> invert() { } @Override - public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> fmap(Function fn) { + public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> fmap(Fn1 fn) { return Monad.super.<_8Prime>fmap(fn).coerce(); } @Override @SuppressWarnings("unchecked") - public <_7Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7Prime, _8> biMapL(Function fn) { + public <_7Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7Prime, _8> biMapL(Fn1 fn) { return (Tuple8<_1, _2, _3, _4, _5, _6, _7Prime, _8>) Bifunctor.super.biMapL(fn); } @Override @SuppressWarnings("unchecked") - public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> biMapR(Function fn) { + public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> biMapR(Fn1 fn) { return (Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime>) Bifunctor.super.biMapR(fn); } @Override public <_7Prime, _8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7Prime, _8Prime> biMap( - Function lFn, - Function rFn) { + Fn1 lFn, + Fn1 rFn) { return new Tuple8<>(_1(), tail().biMap(lFn, rFn)); } @@ -200,10 +200,17 @@ public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> pure(_8Prime _8Prim @Override public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> zip( - Applicative, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>> appFn) { + Applicative, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>> appFn) { return Monad.super.zip(appFn).coerce(); } + @Override + public <_8Prime> Lazy> lazyZip( + Lazy, + Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_8Prime, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>>::coerce); + } + @Override public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> discardL( Applicative<_8Prime, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>> appB) { @@ -218,14 +225,16 @@ public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8> discardR( @Override public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> flatMap( - Function>> f) { + Fn1>> f) { return pure(f.apply(_8).>coerce()._8()); } @Override - @SuppressWarnings("unchecked") - public <_8Prime, App extends Applicative, TravB extends Traversable<_8Prime, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>>, AppB extends Applicative<_8Prime, App>, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public <_8Prime, App extends Applicative, + TravB extends Traversable<_8Prime, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>>, + AppTrav extends Applicative> AppTrav traverse( + Fn1> fn, + Fn1 pure) { return fn.apply(_8).fmap(_8Prime -> fmap(constantly(_8Prime))).fmap(Applicative::coerce).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hmap/HMap.java b/src/main/java/com/jnape/palatable/lambda/adt/hmap/HMap.java index df5cf50d7..e1677d49f 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hmap/HMap.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hmap/HMap.java @@ -17,7 +17,7 @@ import static com.jnape.palatable.lambda.adt.Maybe.maybe; import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; -import static com.jnape.palatable.lambda.lens.functions.View.view; +import static com.jnape.palatable.lambda.optics.functions.View.view; import static java.util.Collections.emptyMap; /** @@ -27,13 +27,13 @@ * @see TypeSafeKey * @see com.jnape.palatable.lambda.adt.hlist.HList */ -public final class HMap implements Iterable> { +public final class HMap implements Iterable, Object>> { private static final HMap EMPTY = new HMap(emptyMap()); - private final Map table; + private final Map, Object> table; - private HMap(Map table) { + private HMap(Map, Object> table) { this.table = table; } @@ -90,7 +90,7 @@ public HMap putAll(HMap hMap) { * @param key the key * @return true if the key is mapped; false otherwise */ - public boolean containsKey(TypeSafeKey key) { + public boolean containsKey(TypeSafeKey key) { return table.containsKey(key); } @@ -100,7 +100,7 @@ public boolean containsKey(TypeSafeKey key) { * @param key the key * @return the updated HMap */ - public HMap remove(TypeSafeKey key) { + public HMap remove(TypeSafeKey key) { return alter(t -> t.remove(key)); } @@ -122,7 +122,7 @@ public HMap removeAll(HMap hMap) { * * @return a {@link Set} of all the mapped keys */ - public Set keys() { + public Set> keys() { return new HashSet<>(table.keySet()); } @@ -141,12 +141,12 @@ public Collection values() { * * @return the map view */ - public Map toMap() { + public Map, Object> toMap() { return new HashMap<>(table); } @Override - public Iterator> iterator() { + public Iterator, Object>> iterator() { return map(Tuple2::fromEntry, table.entrySet()).iterator(); } @@ -171,8 +171,8 @@ public String toString() { '}'; } - private HMap alter(Consumer> alterFn) { - HashMap copy = new HashMap<>(table); + private HMap alter(Consumer, Object>> alterFn) { + HashMap, Object> copy = new HashMap<>(table); alterFn.accept(copy); return new HMap(copy); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hmap/Schema.java b/src/main/java/com/jnape/palatable/lambda/adt/hmap/Schema.java index a7e3eb371..f72b9f8b4 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hmap/Schema.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hmap/Schema.java @@ -11,11 +11,14 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple6; import com.jnape.palatable.lambda.adt.hlist.Tuple7; import com.jnape.palatable.lambda.adt.hlist.Tuple8; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.Both; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.functor.Functor; +import com.jnape.palatable.lambda.functor.Profunctor; +import com.jnape.palatable.lambda.optics.Lens; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; -import static com.jnape.palatable.lambda.lens.lenses.HMapLens.valueAt; +import static com.jnape.palatable.lambda.optics.lenses.HMapLens.valueAt; /** * A lens that focuses on the {@link HList heterogeneous list} of values pointed at by one or more @@ -27,21 +30,33 @@ */ public interface Schema> extends Lens.Simple> { - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "RedundantTypeArguments"}) default > Schema add(TypeSafeKey key) { - return Lens.both(this, valueAt(key)) - .>mapA(into((maybeValues, maybeA) -> maybeValues.zip(maybeA.fmap(a -> values -> (NewValues) values.cons(a))))) - .>mapB(Both.both(maybeNewValues -> maybeNewValues.fmap(HCons::tail), - maybeNewValues -> maybeNewValues.fmap(HCons::head))) - ::apply; + Lens, Maybe> lens = Lens.both(this, valueAt(key)) + .>mapA(into((maybeValues, maybeA) -> maybeValues + .zip(maybeA.fmap(a -> values -> (NewValues) values.cons(a))))) + .>mapB(Both.both(maybeNewValues -> maybeNewValues.fmap(HCons::tail), + maybeNewValues -> maybeNewValues.fmap(HCons::head))); + return new Schema() { + @Override + public >, CoF extends Functor>, FB extends Functor, ? extends CoF>, FT extends Functor, PAFB extends Profunctor, FB, ? extends CoP>, PSFT extends Profunctor> PSFT apply( + PAFB pafb) { + return lens.apply(pafb); + } + }; } - @SuppressWarnings("unchecked") static Schema> schema(TypeSafeKey key) { - return valueAt(key) + Lens>, Maybe>> lens = valueAt(key) .mapA(ma -> ma.fmap(HList::singletonHList)) - .>>mapB(maybeSingletonA -> maybeSingletonA.fmap(HCons::head)) - ::apply; + .mapB(maybeSingletonA -> maybeSingletonA.fmap(HCons::head)); + return new Schema>() { + @Override + public >, CoF extends Functor>, FB extends Functor>, ? extends CoF>, FT extends Functor, PAFB extends Profunctor>, FB, ? extends CoP>, PSFT extends Profunctor> PSFT apply( + PAFB pafb) { + return lens.apply(pafb); + } + }; } static Schema> schema(TypeSafeKey aKey, diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java b/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java index 8bae70949..ce9361693 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java @@ -3,8 +3,8 @@ import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.Profunctor; -import com.jnape.palatable.lambda.lens.Iso; -import com.jnape.palatable.lambda.lens.LensLike; +import com.jnape.palatable.lambda.optics.Iso; +import com.jnape.palatable.lambda.optics.Optic; import java.util.Objects; @@ -23,14 +23,15 @@ */ public interface TypeSafeKey extends Iso.Simple { + @Override - default TypeSafeKey discardR(Applicative> appB) { + default TypeSafeKey discardR(Applicative> appB) { Iso.Simple discarded = Iso.Simple.super.discardR(appB); return new TypeSafeKey() { @Override - public

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

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

, FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply( + default >, + CoF extends Functor>, + FB extends Functor, + FT extends Functor, + PAFB extends Profunctor, + PSFT extends Profunctor> PSFT apply( PAFB pafb) { return (PSFT) pafb; } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/product/Product2.java b/src/main/java/com/jnape/palatable/lambda/adt/product/Product2.java index 4c3d64da0..0a76df761 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/product/Product2.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/product/Product2.java @@ -1,9 +1,9 @@ package com.jnape.palatable.lambda.adt.product; import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn2; import java.util.Map; -import java.util.function.BiFunction; /** * The minimal shape of the combination of two potentially distinctly typed values, supporting destructuring via @@ -35,11 +35,11 @@ public interface Product2<_1, _2> extends Map.Entry<_1, _2> { * Destructure and apply this product to a function accepting the same number of arguments as this product's * slots. This can be thought of as a kind of dual to uncurrying a function and applying a product to it. * - * @param fn the function to apply * @param the return type of the function + * @param fn the function to apply * @return the result of applying the destructured product to the function */ - default R into(BiFunction fn) { + default R into(Fn2 fn) { return fn.apply(_1(), _2()); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/product/Product3.java b/src/main/java/com/jnape/palatable/lambda/adt/product/Product3.java index 063456453..18da0491f 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/product/Product3.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/product/Product3.java @@ -30,7 +30,7 @@ public interface Product3<_1, _2, _3> extends Product2<_1, _2> { * @return the result of applying the destructured product to the function */ default R into(Fn3 fn) { - return Product2.super.into(fn.toBiFunction()).apply(_3()); + return Product2.super.into(fn).apply(_3()); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/adt/product/Product4.java b/src/main/java/com/jnape/palatable/lambda/adt/product/Product4.java index 2703f8229..87a33376d 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/product/Product4.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/product/Product4.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.adt.product; import com.jnape.palatable.lambda.adt.hlist.Tuple4; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn4; /** @@ -31,7 +32,7 @@ public interface Product4<_1, _2, _3, _4> extends Product3<_1, _2, _3> { * @return the result of applying the destructured product to the function */ default R into(Fn4 fn) { - return Product3.super.into(fn).apply(_4()); + return Product3.super.>into(fn).apply(_4()); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java index 5c36ff861..648c42eab 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java @@ -1,74 +1,116 @@ package com.jnape.palatable.lambda.functions; import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.functions.specialized.SideEffect; import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.internal.Runtime; +import com.jnape.palatable.lambda.io.IO; import java.util.function.Consumer; -import java.util.function.Function; -import static com.jnape.palatable.lambda.functions.Fn0.fn0; -import static com.jnape.palatable.lambda.functions.IO.io; +import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.specialized.SideEffect.NOOP; +import static com.jnape.palatable.lambda.io.IO.io; /** * A function returning "no result", and therefore only useful as a side-effect. * * @param the argument type * @see Fn0 - * @see Consumer */ @FunctionalInterface -public interface Effect extends Fn1>, Consumer { +public interface Effect extends Fn1> { @Override - default IO apply(A a) { - return io(fn0(() -> accept(a))); + IO checkedApply(A a) throws Throwable; + + /** + * Convert this {@link Effect} to a java {@link Consumer} + * + * @return the {@link Consumer} + */ + default Consumer toConsumer() { + return a -> apply(a).unsafePerformIO(); } + /** + * {@inheritDoc} + */ @Override - default Effect diMapL(Function fn) { - return effect(Fn1.super.diMapL(fn)); + default IO apply(A a) { + try { + return checkedApply(a); + } catch (Throwable t) { + throw Runtime.throwChecked(t); + } } + /** + * Left-to-right composition of {@link Effect Effects}. + * + * @param effect the other {@link Effect} + * @return the composed {@link Effect} + */ + default Effect andThen(Effect effect) { + return a -> apply(a).flatMap(constantly(effect.apply(a))); + } + + /** + * {@inheritDoc} + */ @Override - default Effect contraMap(Function fn) { - return effect(Fn1.super.contraMap(fn)); + default Effect diMapL(Fn1 fn) { + return effect(Fn1.super.diMapL(fn)); } + /** + * {@inheritDoc} + */ @Override - default Effect compose(Function before) { - return effect(Fn1.super.compose(before)); + default Effect contraMap(Fn1 fn) { + return effect(Fn1.super.contraMap(fn)); } + /** + * {@inheritDoc} + */ @Override default Effect discardR(Applicative> appB) { return effect(Fn1.super.discardR(appB)); } - @Override - default Effect andThen(Consumer after) { - return Consumer.super.andThen(after)::accept; + /** + * Static factory method to create an {@link Effect} from a java {@link Consumer}. + * + * @param consumer the {@link Consumer} + * @param the input type + * @return the {@link Effect} + */ + static Effect fromConsumer(Consumer consumer) { + return a -> io(() -> consumer.accept(a)); } /** - * Static factory method to aid in inference. + * Create an {@link Effect} from a {@link SideEffect}; * - * @param effect the effect - * @param the effect argument type - * @return the effect + * @param sideEffect the {@link SideEffect} + * @param any desired input type + * @return the {@link Effect} */ - static Effect effect(Consumer effect) { - return effect::accept; + static Effect effect(SideEffect sideEffect) { + return effect(constantly(io(sideEffect))); } /** - * Create an {@link Effect} from a {@link Runnable}; + * Create an {@link Effect} that accepts an input and does nothing; * - * @param runnable the runnable - * @return the effect + * @param any desired input type + * @return the noop {@link Effect} */ - static Effect effect(Runnable runnable) { - return effect(constantly(io(runnable))); + @SuppressWarnings("unused") + static Effect noop() { + return effect(NOOP); } /** @@ -78,7 +120,7 @@ static Effect effect(Runnable runnable) { * @param the effect argument type * @return the effect */ - static Effect effect(Fn1> fn) { - return a -> fn.apply(a).unsafePerformIO(); + static Effect effect(Fn1> fn) { + return fn.fmap(io -> io.fmap(constantly(UNIT)))::apply; } } \ No newline at end of file diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java index 84eb3e4a8..3352046fe 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java @@ -5,43 +5,64 @@ 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>. * * @param the result type * @see Fn1 - * @see Supplier * @see Callable */ @FunctionalInterface -public interface Fn0 extends Fn1, Supplier, Callable { +public interface Fn0 extends Fn1 { - A apply(); + A checkedApply() throws Throwable; /** - * Invoke this function with {@link Unit}. + * Convenience method for applying this {@link Fn0} without providing an explicit {@link Unit}. * - * @param unit the only allowed input - * @return the result value + * @return the result + */ + default A apply() { + return apply(UNIT); + } + + /** + * Convert this {@link Fn0} to a java {@link Supplier} + * + * @return the {@link Supplier} + */ + default Supplier toSupplier() { + return this::apply; + } + + /** + * Convert this {@link Fn0} to a java {@link Callable} + * + * @return the {@link Callable} + */ + default Callable toCallable() { + return this::apply; + } + + /** + * {@inheritDoc} */ @Override - default A apply(Unit unit) { - return apply(); + default A checkedApply(Unit unit) throws Throwable { + return checkedApply(); } @Override - default Fn0 flatMap(Function>> f) { + default Fn0 flatMap(Fn1>> f) { return Fn1.super.flatMap(f).thunk(UNIT); } @Override - default Fn0 fmap(Function f) { + default Fn0 fmap(Fn1 f) { return Fn1.super.fmap(f).thunk(UNIT); } @@ -51,7 +72,7 @@ default Fn0 pure(B b) { } @Override - default Fn0 zip(Applicative, Fn1> appFn) { + default Fn0 zip(Applicative, Fn1> appFn) { return Fn1.super.zip(appFn).thunk(UNIT); } @@ -71,30 +92,10 @@ default Fn0 discardR(Applicative> appB) { } @Override - default Fn0 diMapR(Function fn) { + default Fn0 diMapR(Fn1 fn) { return Fn1.super.diMapR(fn).thunk(UNIT); } - @Override - default Fn1 compose(Function before) { - return Fn1.super.compose(before)::apply; - } - - @Override - default Fn0 andThen(Function after) { - return Fn1.super.andThen(after).thunk(UNIT); - } - - @Override - default A get() { - return apply(); - } - - @Override - default A call() { - return apply(); - } - /** * Convenience method for converting a {@link Supplier} to an {@link Fn0}. * @@ -102,39 +103,41 @@ default A call() { * @param the output type * @return the {@link Fn0} */ - static Fn0 fn0(Supplier supplier) { + static Fn0 fromSupplier(Supplier supplier) { return supplier::get; } /** - * Static factory method for coercing a lambda to an {@link Fn0}. + * Convenience method for converting a {@link Callable} to an {@link Fn0}. * - * @param fn the lambda to coerce - * @param the output type + * @param callable the callable + * @param the output type * @return the {@link Fn0} */ - static Fn0 fn0(Fn0 fn) { - return fn; + static Fn0 fromCallable(Callable callable) { + return callable::call; } /** - * Static factory method for adapting a {@link Runnable} to an {@link Fn0}<{@link Unit}>. + * Static factory method for coercing a lambda to an {@link Fn0}. * - * @param runnable the {@link Runnable} + * @param fn the lambda to coerce + * @param the output type * @return the {@link Fn0} */ - static Fn0 fn0(Runnable runnable) { - return io(runnable)::unsafePerformIO; + static Fn0 fn0(Fn0 fn) { + return fn; } /** - * Static factory method for adapting a {@link Function} to an {@link Fn0}. + * Static factory method for adapting an {@link Fn1}<Unit, A> to an + * {@link Fn0}<A>. * - * @param fn the {@link Function} + * @param fn the {@link Fn1} * @param the output type * @return the {@link Fn0} */ - static Fn0 fn0(Function fn) { + static Fn0 fn0(Fn1 fn) { return fn0(() -> fn.apply(UNIT)); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java index c9fa0ee26..d08195f42 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java @@ -1,14 +1,18 @@ package com.jnape.palatable.lambda.functions; +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.adt.choice.Choice2; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.functor.Strong; +import com.jnape.palatable.lambda.functor.Cartesian; +import com.jnape.palatable.lambda.functor.Cocartesian; +import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.internal.Runtime; import com.jnape.palatable.lambda.monad.Monad; -import java.util.function.BiFunction; import java.util.function.Function; -import static com.jnape.palatable.lambda.functions.Fn2.fn2; +import static com.jnape.palatable.lambda.functions.Fn2.curried; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; /** @@ -19,15 +23,33 @@ * @param The result type */ @FunctionalInterface -public interface Fn1 extends Monad>, Strong, Function { +public interface Fn1 extends + Monad>, + Cartesian>, + Cocartesian> { /** - * Invoke this function with the given argument. + * Invoke this function explosively with the given argument. * * @param a the argument * @return the result of the function application */ - B apply(A a); + default B apply(A a) { + try { + return checkedApply(a); + } catch (Throwable t) { + throw Runtime.throwChecked(t); + } + } + + /** + * Invoke this function with the given argument, potentially throwing any {@link Throwable}. + * + * @param a the argument + * @return the result of the function application + * @throws Throwable anything possibly thrown by the function + */ + B checkedApply(A a) throws Throwable; /** * Convert this {@link Fn1} to an {@link Fn0} by supplying an argument to this function. Useful for fixing an @@ -47,11 +69,23 @@ default Fn0 thunk(A a) { * @return the widened function */ default Fn2 widen() { - return fn2(constantly(this)); + return curried(constantly(this)); + } + + /** + * Convert this {@link Fn1} to a java {@link Function}. + * + * @return the {@link Function} + */ + default Function toFunction() { + return this::apply; } + /** + * {@inheritDoc} + */ @Override - default Fn1 flatMap(Function>> f) { + default Fn1 flatMap(Fn1>> f) { return a -> f.apply(apply(a)).>coerce().apply(a); } @@ -63,8 +97,8 @@ default Fn1 flatMap(Function>> * @return a function representing the composition of this function and f */ @Override - default Fn1 fmap(Function f) { - return Monad.super.fmap(f).coerce(); + default Fn1 fmap(Fn1 f) { + return a -> f.apply(apply(a)); } /** @@ -79,8 +113,8 @@ default Fn1 pure(C c) { * {@inheritDoc} */ @Override - default Fn1 zip(Applicative, Fn1> appFn) { - return a -> appFn.>>coerce().apply(a).apply(apply(a)); + default Fn1 zip(Applicative, Fn1> appFn) { + return Monad.super.zip(appFn).coerce(); } /** @@ -88,7 +122,15 @@ default Fn1 zip(Applicative, Fn1 Fn1 zip(Fn2 appFn) { - return zip((Fn1>) (Object) appFn); + return zip((Fn1>) (Object) appFn); + } + + /** + * {@inheritDoc} + */ + @Override + default Lazy> lazyZip(Lazy, Fn1>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); } /** @@ -116,8 +158,8 @@ default Fn1 discardR(Applicative> appB) { * @return an {@link Fn1}<Z, B> */ @Override - default Fn1 diMapL(Function fn) { - return (Fn1) Strong.super.diMapL(fn); + default Fn1 diMapL(Fn1 fn) { + return (Fn1) Cartesian.super.diMapL(fn); } /** @@ -129,8 +171,8 @@ default Fn1 diMapL(Function fn) { * @return an {@link Fn1}<A, C> */ @Override - default Fn1 diMapR(Function fn) { - return (Fn1) Strong.super.diMapR(fn); + default Fn1 diMapR(Fn1 fn) { + return (Fn1) Cartesian.super.diMapR(fn); } /** @@ -143,8 +185,8 @@ default Fn1 diMapR(Function fn) { * @return an {@link Fn1}<Z, C> */ @Override - default Fn1 diMap(Function lFn, Function rFn) { - return lFn.andThen(this).andThen(rFn)::apply; + default Fn1 diMap(Fn1 lFn, Fn1 rFn) { + return lFn.fmap(this).fmap(rFn)::apply; } /** @@ -154,43 +196,45 @@ default Fn1 diMap(Function lFn, Function Fn1, Tuple2> strengthen() { + default Fn1, Tuple2> cartesian() { return t -> t.fmap(this); } + /** + * {@inheritDoc} + */ + @Override default Fn1> carry() { - return (Fn1>) Strong.super.carry(); + return (Fn1>) Cartesian.super.carry(); } + /** + * Choose between either applying this function or returning back a different result altogether. + * + * @param the potentially different result + * @return teh strengthened {@link Fn1} + */ @Override - default Fn1 contraMap(Function fn) { - return (Fn1) Strong.super.contraMap(fn); + default Fn1, Choice2> cocartesian() { + return a -> a.fmap(this); } /** - * Override of {@link Function#compose(Function)}, returning an instance of {@link Fn1} for compatibility. - * Right-to-left composition. + * Choose between a successful result b or returning back the input, a. * - * @param before the function who's return value is this function's argument - * @param the new argument type - * @return an {@link Fn1}<Z, B> + * @return an {@link Fn1} that chooses between its input (in case of failure) or its output. */ @Override - default Fn1 compose(Function before) { - return z -> apply(before.apply(z)); + default Fn1> choose() { + return a -> Either.trying(() -> apply(a), constantly(a)).match(Choice2::a, Choice2::b); } /** - * Right-to-left composition between different arity functions. Preserves highest arity in the return type, - * specialized to lambda types (in this case, {@link BiFunction} -> {@link Fn2}). - * - * @param before the function to pass its return value to this function's input - * @param the resulting function's first argument type - * @param the resulting function's second argument type - * @return an {@link Fn2}<Y, Z, B> + * {@inheritDoc} */ - default Fn2 compose(BiFunction before) { - return compose(fn2(before)); + @Override + default Fn1 contraMap(Fn1 fn) { + return (Fn1) Cartesian.super.contraMap(fn); } /** @@ -202,45 +246,42 @@ default Fn2 compose(BiFunction Fn2 compose(Fn2 before) { - return fn2(before.fmap(this::compose))::apply; + return curried(before.fmap(this::contraMap))::apply; } /** - * Left-to-right composition between different arity functions. Preserves highest arity in the return type, - * specialized to lambda types (in this case, {@link BiFunction} -> {@link Fn2}). + * Left-to-right composition between different arity functions. Preserves highest arity in the return type. * * @param after the function to invoke on this function's return value * @param the resulting function's second argument type * @param the resulting function's return type * @return an {@link Fn2}<A, C, D> */ - default Fn2 andThen(BiFunction after) { + default Fn2 andThen(Fn2 after) { return (a, c) -> after.apply(apply(a), c); } /** - * Override of {@link Function#andThen(Function)}, returning an instance of {@link Fn1} for compatibility. - * Left-to-right composition. + * Static factory method for avoid explicit casting when using method references as {@link Fn1}s. * - * @param after the function to invoke on this function's return value - * @param the new result type - * @return an {@link Fn1}<A, C> + * @param fn the function to adapt + * @param the input type + * @param the output type + * @return the {@link Fn1} */ - @Override - default Fn1 andThen(Function after) { - return a -> after.apply(apply(a)); + static Fn1 fn1(Fn1 fn) { + return fn::apply; } /** - * Static factory method for wrapping a {@link Function} in an {@link Fn1}. Useful for avoid explicit casting when - * using method references as {@link Fn1}s. + * Static factory method for wrapping a java {@link Function} in an {@link Fn1}. * - * @param function the function to adapt - * @param the input argument type + * @param function the function + * @param the input type * @param the output type * @return the {@link Fn1} */ - static Fn1 fn1(Function function) { + static Fn1 fromFunction(Function function) { return function::apply; } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java index dd116a80f..0528ff71a 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java @@ -2,9 +2,9 @@ import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.internal.Runtime; import java.util.function.BiFunction; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.Fn3.fn3; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; @@ -23,6 +23,8 @@ @FunctionalInterface public interface Fn2 extends Fn1> { + C checkedApply(A a, B b) throws Throwable; + /** * Invoke this function with the given arguments. * @@ -30,26 +32,28 @@ public interface Fn2 extends Fn1> { * @param b the second argument * @return the result of the function application */ - C apply(A a, B b); + default C apply(A a, B b) { + try { + return checkedApply(a, b); + } catch (Throwable t) { + throw Runtime.throwChecked(t); + } + } /** * {@inheritDoc} */ @Override - default Fn3 widen() { - return fn3(constantly(this)); + default Fn1 checkedApply(A a) throws Throwable { + return b -> checkedApply(a, b); } /** - * Same as normal composition, except that the result is an instance of {@link Fn2} for convenience. - * - * @param before the function who's return value is this function's argument - * @param the new argument type - * @return an {@link Fn2}<Z, B, C> + * {@inheritDoc} */ @Override - default Fn2 compose(Function before) { - return fn2(Fn1.super.compose(before)); + default Fn3 widen() { + return fn3(constantly(this)); } /** @@ -91,34 +95,40 @@ default BiFunction toBiFunction() { return this::apply; } + /** + * {@inheritDoc} + */ @Override default Fn2 discardR(Applicative> appB) { - return fn2(Fn1.super.discardR(appB)); - } - - @Override - default Fn2 diMapL(Function fn) { - return fn2(Fn1.super.diMapL(fn)); + return curried(Fn1.super.discardR(appB)); } + /** + * {@inheritDoc} + */ @Override - default Fn2 contraMap(Function fn) { - return fn2(Fn1.super.contraMap(fn)); + default Fn2 diMapL(Fn1 fn) { + return curried(Fn1.super.diMapL(fn)); } + /** + * {@inheritDoc} + */ @Override - default Fn3 compose(BiFunction before) { - return fn3(Fn1.super.compose(before)); + default Fn2 contraMap(Fn1 fn) { + return curried(Fn1.super.contraMap(fn)); } + /** + * {@inheritDoc} + */ @Override default Fn3 compose(Fn2 before) { return fn3(Fn1.super.compose(before)); } /** - * Static factory method for wrapping a {@link BiFunction} in an {@link Fn2}. Useful for avoid explicit casting when - * using method references as {@link Fn2}s. + * Static factory method for wrapping a {@link BiFunction} in an {@link Fn2}. * * @param biFunction the biFunction to adapt * @param the first input argument type @@ -126,7 +136,7 @@ default Fn3 compose(Fn2 be * @param the output type * @return the {@link Fn2} */ - static Fn2 fn2(BiFunction biFunction) { + static Fn2 fromBiFunction(BiFunction biFunction) { return biFunction::apply; } @@ -139,7 +149,20 @@ static Fn2 fn2(BiFunction * @param the output type * @return the {@link Fn2} */ - static Fn2 fn2(Fn1> curriedFn1) { + static Fn2 curried(Fn1> curriedFn1) { return (a, b) -> curriedFn1.apply(a).apply(b); } + + /** + * Static method to aid inference. + * + * @param fn2 the {@link Fn2} + * @param the first input type + * @param the second input type + * @param the output type + * @return the {@link Fn2} + */ + static Fn2 fn2(Fn2 fn2) { + return fn2; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java index 9178520dc..881d848ff 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java @@ -2,9 +2,7 @@ import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functor.Applicative; - -import java.util.function.BiFunction; -import java.util.function.Function; +import com.jnape.palatable.lambda.internal.Runtime; import static com.jnape.palatable.lambda.functions.Fn4.fn4; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; @@ -21,6 +19,8 @@ @FunctionalInterface public interface Fn3 extends Fn2> { + D checkedApply(A a, B b, C c) throws Throwable; + /** * Invoke this function with the given arguments. * @@ -29,7 +29,21 @@ public interface Fn3 extends Fn2> { * @param c the third argument * @return the result of the function application */ - D apply(A a, B b, C c); + default D apply(A a, B b, C c) { + try { + return checkedApply(a, b, c); + } catch (Throwable t) { + throw Runtime.throwChecked(t); + } + } + + /** + * {@inheritDoc} + */ + @Override + default Fn1 checkedApply(A a, B b) throws Throwable { + return c -> checkedApply(a, b, c); + } /** * {@inheritDoc} @@ -89,20 +103,15 @@ default Fn3 discardR(Applicative> appB) { } @Override - default Fn3 diMapL(Function fn) { + default Fn3 diMapL(Fn1 fn) { return fn3(Fn2.super.diMapL(fn)); } @Override - default Fn3 contraMap(Function fn) { + default Fn3 contraMap(Fn1 fn) { return fn3(Fn2.super.contraMap(fn)); } - @Override - default Fn4 compose(BiFunction before) { - return fn4(Fn2.super.compose(before)); - } - @Override default Fn4 compose(Fn2 before) { return fn4(Fn2.super.compose(before)); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java index 4f9ea02de..f2e9f7d47 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java @@ -2,9 +2,7 @@ import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functor.Applicative; - -import java.util.function.BiFunction; -import java.util.function.Function; +import com.jnape.palatable.lambda.internal.Runtime; import static com.jnape.palatable.lambda.functions.Fn5.fn5; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; @@ -22,6 +20,8 @@ @FunctionalInterface public interface Fn4 extends Fn3> { + E checkedApply(A a, B b, C c, D d) throws Throwable; + /** * Invoke this function with the given arguments. * @@ -31,7 +31,21 @@ public interface Fn4 extends Fn3> { * @param d the fourth argument * @return the result of the function application */ - E apply(A a, B b, C c, D d); + default E apply(A a, B b, C c, D d) { + try { + return checkedApply(a, b, c, d); + } catch (Throwable t) { + throw Runtime.throwChecked(t); + } + } + + /** + * {@inheritDoc} + */ + @Override + default Fn1 checkedApply(A a, B b, C c) throws Throwable { + return d -> checkedApply(a, b, c, d); + } /** * {@inheritDoc} @@ -104,20 +118,15 @@ default Fn4 discardR(Applicative> appB) { } @Override - default Fn4 diMapL(Function fn) { + default Fn4 diMapL(Fn1 fn) { return fn4(Fn3.super.diMapL(fn)); } @Override - default Fn4 contraMap(Function fn) { + default Fn4 contraMap(Fn1 fn) { return fn4(Fn3.super.contraMap(fn)); } - @Override - default Fn5 compose(BiFunction before) { - return fn5(Fn3.super.compose(before)); - } - @Override default Fn5 compose(Fn2 before) { return fn5(Fn3.super.compose(before)); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java index f37f664e0..c89b8dadd 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java @@ -2,9 +2,7 @@ import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functor.Applicative; - -import java.util.function.BiFunction; -import java.util.function.Function; +import com.jnape.palatable.lambda.internal.Runtime; import static com.jnape.palatable.lambda.functions.Fn6.fn6; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; @@ -23,6 +21,8 @@ @FunctionalInterface public interface Fn5 extends Fn4> { + F checkedApply(A a, B b, C c, D d, E e) throws Throwable; + /** * Invoke this function with the given arguments. * @@ -33,7 +33,22 @@ public interface Fn5 extends Fn4> { * @param e the fifth argument * @return the result of the function application */ - F apply(A a, B b, C c, D d, E e); + default F apply(A a, B b, C c, D d, E e) { + try { + return checkedApply(a, b, c, d, e); + } catch (Throwable t) { + throw Runtime.throwChecked(t); + } + + } + + /** + * {@inheritDoc} + */ + @Override + default Fn1 checkedApply(A a, B b, C c, D d) throws Throwable { + return e -> checkedApply(a, b, c, d, e); + } /** * {@inheritDoc} @@ -120,20 +135,15 @@ default Fn5 discardR(Applicative> appB) { } @Override - default Fn5 diMapL(Function fn) { + default Fn5 diMapL(Fn1 fn) { return fn5(Fn4.super.diMapL(fn)); } @Override - default Fn5 contraMap(Function fn) { + default Fn5 contraMap(Fn1 fn) { return fn5(Fn4.super.contraMap(fn)); } - @Override - default Fn6 compose(BiFunction before) { - return fn6(Fn4.super.compose(before)); - } - @Override default Fn6 compose(Fn2 before) { return fn6(Fn4.super.compose(before)); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java index 69c6619cb..4e7bbea89 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java @@ -2,9 +2,7 @@ import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functor.Applicative; - -import java.util.function.BiFunction; -import java.util.function.Function; +import com.jnape.palatable.lambda.internal.Runtime; import static com.jnape.palatable.lambda.functions.Fn7.fn7; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; @@ -24,6 +22,8 @@ @FunctionalInterface public interface Fn6 extends Fn5> { + G checkedApply(A a, B b, C c, D d, E e, F f) throws Throwable; + /** * Invoke this function with the given arguments. * @@ -35,7 +35,22 @@ public interface Fn6 extends Fn5> * @param f the sixth argument * @return the result of the function application */ - G apply(A a, B b, C c, D d, E e, F f); + default G apply(A a, B b, C c, D d, E e, F f) { + try { + return checkedApply(a, b, c, d, e, f); + } catch (Throwable t) { + throw Runtime.throwChecked(t); + } + + } + + /** + * {@inheritDoc} + */ + @Override + default Fn1 checkedApply(A a, B b, C c, D d, E e) throws Throwable { + return f -> checkedApply(a, b, c, d, e, f); + } /** * {@inheritDoc} @@ -137,20 +152,15 @@ default Fn6 discardR(Applicative> appB) { } @Override - default Fn6 diMapL(Function fn) { + default Fn6 diMapL(Fn1 fn) { return fn6(Fn5.super.diMapL(fn)); } @Override - default Fn6 contraMap(Function fn) { + default Fn6 contraMap(Fn1 fn) { return fn6(Fn5.super.contraMap(fn)); } - @Override - default Fn7 compose(BiFunction before) { - return fn7(Fn5.super.compose(before)); - } - @Override default Fn7 compose(Fn2 before) { return fn7(Fn5.super.compose(before)); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java index 90feae545..2d27e6be2 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java @@ -2,9 +2,7 @@ import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functor.Applicative; - -import java.util.function.BiFunction; -import java.util.function.Function; +import com.jnape.palatable.lambda.internal.Runtime; import static com.jnape.palatable.lambda.functions.Fn8.fn8; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; @@ -25,6 +23,8 @@ @FunctionalInterface public interface Fn7 extends Fn6> { + H checkedApply(A a, B b, C c, D d, E e, F f, G g) throws Throwable; + /** * Invoke this function with the given arguments. * @@ -37,7 +37,21 @@ public interface Fn7 extends Fn6 checkedApply(A a, B b, C c, D d, E e, F f) throws Throwable { + return g -> checkedApply(a, b, c, d, e, f, g); + } /** * {@inheritDoc} @@ -155,20 +169,15 @@ default Fn7 discardR(Applicative> appB) } @Override - default Fn7 diMapL(Function fn) { + default Fn7 diMapL(Fn1 fn) { return fn7(Fn6.super.diMapL(fn)); } @Override - default Fn7 contraMap(Function fn) { + default Fn7 contraMap(Fn1 fn) { return fn7(Fn6.super.contraMap(fn)); } - @Override - default Fn8 compose(BiFunction before) { - return fn8(Fn6.super.compose(before)); - } - @Override default Fn8 compose(Fn2 before) { return fn8(Fn6.super.compose(before)); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java index 9d5020687..a38e74eb1 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java @@ -2,9 +2,7 @@ import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functor.Applicative; - -import java.util.function.BiFunction; -import java.util.function.Function; +import com.jnape.palatable.lambda.internal.Runtime; /** * A function taking six arguments. Defined in terms of {@link Fn7}, so similarly auto-curried. @@ -23,6 +21,8 @@ @FunctionalInterface public interface Fn8 extends Fn7> { + I checkedApply(A a, B b, C c, D d, E e, F f, G g, H h) throws Throwable; + /** * Invoke this function with the given arguments. * @@ -36,7 +36,21 @@ public interface Fn8 extends Fn7 checkedApply(A a, B b, C c, D d, E e, F f, G g) throws Throwable { + return h -> checkedApply(a, b, c, d, e, f, g, h); + } /** * Partially apply this function by taking its first argument. @@ -163,21 +177,15 @@ default Fn8 discardR(Applicative> ap } @Override - default Fn8 diMapL(Function fn) { + default Fn8 diMapL(Fn1 fn) { return fn8(Fn7.super.diMapL(fn)); } @Override - default Fn8 contraMap(Function fn) { + default Fn8 contraMap(Fn1 fn) { return fn8(Fn7.super.contraMap(fn)); } - @Override - default Fn8> compose( - BiFunction before) { - return Fn7.super.compose(before); - } - @Override default Fn8> compose(Fn2 before) { return Fn7.super.compose(before); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/IO.java b/src/main/java/com/jnape/palatable/lambda/functions/IO.java deleted file mode 100644 index cb0ce4c07..000000000 --- a/src/main/java/com/jnape/palatable/lambda/functions/IO.java +++ /dev/null @@ -1,244 +0,0 @@ -package com.jnape.palatable.lambda.functions; - -import com.jnape.palatable.lambda.adt.Try; -import com.jnape.palatable.lambda.adt.Unit; -import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.monad.Monad; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; -import java.util.function.Function; -import java.util.function.Supplier; - -import static com.jnape.palatable.lambda.adt.Unit.UNIT; -import static com.jnape.palatable.lambda.functions.specialized.checked.CheckedSupplier.checked; -import static java.util.concurrent.CompletableFuture.supplyAsync; - -/** - * A {@link Monad} representing some side-effecting computation to be performed. Note that because {@link IO} inherently - * offers an interface supporting parallelism, the optimal execution strategy for any given {@link IO} is encoded in - * its composition. - * - * @param the result type - */ -public interface IO extends Monad> { - - /** - * Run the effect represented by this {@link IO} instance, blocking the current thread until the effect terminates. - * - * @return the result of the effect - */ - A unsafePerformIO(); - - /** - * Returns a {@link CompletableFuture} representing the result of this eventual effect. By default, this will - * immediately run the effect in terms of the implicit {@link Executor} available to {@link CompletableFuture} - * (usually the {@link java.util.concurrent.ForkJoinPool}). Note that specific {@link IO} constructions may allow - * this method to delegate to externally-managed {@link CompletableFuture} instead of synthesizing their own. - * - * @return the {@link CompletableFuture} representing this {@link IO}'s eventual result - * @see IO#unsafePerformAsyncIO(Executor) - */ - default CompletableFuture unsafePerformAsyncIO() { - return supplyAsync(this::unsafePerformIO); - } - - /** - * Returns a {@link CompletableFuture} representing the result of this eventual effect. By default, this will - * immediately run the effect in terms of the provided {@link Executor}. Note that specific {@link IO} - * constructions may allow this method to delegate to externally-managed {@link CompletableFuture} instead of - * synthesizing their own. - * - * @param executor the {@link Executor} to run the {@link CompletableFuture} from - * @return the {@link CompletableFuture} representing this {@link IO}'s eventual result - * @see IO#unsafePerformAsyncIO() - */ - default CompletableFuture unsafePerformAsyncIO(Executor executor) { - return supplyAsync(this::unsafePerformIO, executor); - } - - /** - * Given a function from any {@link Throwable} to the result type A, if this {@link IO} successfully - * yields a result, return it; otherwise, map the {@link Throwable} to the result type and return that. - * - * @param recoveryFn the recovery function - * @return the guarded {@link IO} - */ - default IO exceptionally(Function recoveryFn) { - return new IO() { - @Override - public A unsafePerformIO() { - return Try.trying(IO.this::unsafePerformIO).recover(recoveryFn); - } - - @Override - public CompletableFuture unsafePerformAsyncIO() { - return IO.this.unsafePerformAsyncIO().exceptionally(recoveryFn::apply); - } - - @Override - public CompletableFuture unsafePerformAsyncIO(Executor executor) { - return IO.this.unsafePerformAsyncIO(executor).exceptionally(recoveryFn::apply); - } - }; - } - - /** - * {@inheritDoc} - */ - @Override - default IO flatMap(Function>> f) { - return new IO() { - @Override - public B unsafePerformIO() { - return f.apply(IO.this.unsafePerformIO()).>coerce().unsafePerformIO(); - } - - @Override - public CompletableFuture unsafePerformAsyncIO() { - return IO.this.unsafePerformAsyncIO() - .thenCompose(a -> f.apply(a).>coerce().unsafePerformAsyncIO()); - } - - @Override - public CompletableFuture unsafePerformAsyncIO(Executor executor) { - return IO.this.unsafePerformAsyncIO(executor) - .thenCompose(a -> f.apply(a).>coerce().unsafePerformAsyncIO(executor)); - } - }; - } - - /** - * {@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) { - IO ioA = this; - IO> ioF = appFn.coerce(); - return new IO() { - @Override - public B unsafePerformIO() { - return ioF.unsafePerformIO().apply(ioA.unsafePerformIO()); - } - - @Override - public CompletableFuture unsafePerformAsyncIO() { - return ioF.unsafePerformAsyncIO().thenCompose(ioA.unsafePerformAsyncIO()::thenApply); - } - - @Override - public CompletableFuture unsafePerformAsyncIO(Executor executor) { - return ioF.unsafePerformAsyncIO(executor).thenCompose(ioA.unsafePerformAsyncIO(executor)::thenApply); - } - }; - } - - /** - * {@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)); - } - - /** - * Static factory method for creating an {@link IO} from an externally managed source of - * {@link CompletableFuture completable futures}. - *

- * Note that constructing an {@link IO} this way results in no intermediate futures being constructed by either - * {@link IO#unsafePerformAsyncIO()} or {@link IO#unsafePerformAsyncIO(Executor)}, and {@link IO#unsafePerformIO()} - * is synonymous with invoking {@link CompletableFuture#get()} on the externally managed future. - * - * @param supplier the source of externally managed {@link CompletableFuture completable futures} - * @param the result type - * @return the {@link IO} - */ - static IO externallyManaged(Supplier> supplier) { - return new IO() { - @Override - public A unsafePerformIO() { - return checked(() -> unsafePerformAsyncIO().get()).get(); - } - - @Override - public CompletableFuture unsafePerformAsyncIO() { - return supplier.get(); - } - - @Override - public CompletableFuture unsafePerformAsyncIO(Executor executor) { - return supplier.get(); - } - }; - } -} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/CatMaybes.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/CatMaybes.java index 64b9e0a4c..9833e2a32 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/CatMaybes.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/CatMaybes.java @@ -15,20 +15,20 @@ * @param the {@link Maybe} element type, as well as the resulting {@link Iterable} element type */ public final class CatMaybes implements Fn1>, Iterable> { - private static final CatMaybes INSTANCE = new CatMaybes(); + private static final CatMaybes INSTANCE = new CatMaybes<>(); private CatMaybes() { } @Override - public Iterable apply(Iterable> maybes) { + public Iterable checkedApply(Iterable> maybes) { return flatten(map(m -> m.>fmap(Collections::singletonList) .orElse(Collections::emptyIterator), maybes)); } @SuppressWarnings("unchecked") public static CatMaybes catMaybes() { - return INSTANCE; + return (CatMaybes) INSTANCE; } public static Iterable catMaybes(Iterable> as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Coalesce.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Coalesce.java index e97fe056f..3154e07ea 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Coalesce.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Coalesce.java @@ -25,13 +25,13 @@ */ public final class Coalesce implements Fn1>, Either, Iterable>> { - private static final Coalesce INSTANCE = new Coalesce(); + private static final Coalesce INSTANCE = new Coalesce<>(); private Coalesce() { } @Override - public Either, Iterable> apply(Iterable> eithers) { + public Either, Iterable> checkedApply(Iterable> eithers) { return foldLeft((acc, e) -> acc .biMapL(ls -> e.match(Snoc.snoc().flip().apply(ls), constantly(ls))) .flatMap(rs -> e.biMap(Collections::singletonList, @@ -42,7 +42,7 @@ public Either, Iterable> apply(Iterable> eithers) { @SuppressWarnings("unchecked") public static Coalesce coalesce() { - return INSTANCE; + return (Coalesce) INSTANCE; } public static Either, Iterable> coalesce(Iterable> eithers) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Constantly.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Constantly.java index 9f89da517..252eb53df 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Constantly.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Constantly.java @@ -11,19 +11,19 @@ */ public final class Constantly implements Fn2 { - private static final Constantly INSTANCE = new Constantly(); + private static final Constantly INSTANCE = new Constantly<>(); private Constantly() { } @Override - public A apply(A a, B b) { + public A checkedApply(A a, B b) { return a; } @SuppressWarnings("unchecked") public static Constantly constantly() { - return INSTANCE; + return (Constantly) INSTANCE; } public static Fn1 constantly(A a) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Cycle.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Cycle.java index 652b5470d..a5aaaa25b 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Cycle.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Cycle.java @@ -1,7 +1,7 @@ package com.jnape.palatable.lambda.functions.builtin.fn1; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.iteration.CyclicIterable; +import com.jnape.palatable.lambda.internal.iteration.CyclicIterable; import static java.util.Arrays.asList; @@ -13,19 +13,19 @@ */ public final class Cycle implements Fn1, Iterable> { - private static final Cycle INSTANCE = new Cycle(); + private static final Cycle INSTANCE = new Cycle<>(); private Cycle() { } @Override - public Iterable apply(Iterable as) { + public Iterable checkedApply(Iterable as) { return new CyclicIterable<>(as); } @SuppressWarnings("unchecked") public static Cycle cycle() { - return INSTANCE; + return (Cycle) INSTANCE; } public static Iterable cycle(Iterable as) { @@ -33,6 +33,7 @@ public static Iterable cycle(Iterable as) { } @SafeVarargs + @SuppressWarnings("varargs") public static Iterable cycle(A... as) { return cycle(asList(as)); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Distinct.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Distinct.java index 8b39ac2a4..30b97dec4 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Distinct.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Distinct.java @@ -1,7 +1,7 @@ package com.jnape.palatable.lambda.functions.builtin.fn1; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.iteration.DistinctIterable; +import com.jnape.palatable.lambda.internal.iteration.DistinctIterable; /** * Return an {@link Iterable} of the distinct values from the given input {@link Iterable}. @@ -9,19 +9,19 @@ * @param the Iterable element type */ public final class Distinct implements Fn1, Iterable> { - private static final Distinct INSTANCE = new Distinct(); + private static final Distinct INSTANCE = new Distinct<>(); private Distinct() { } @Override - public Iterable apply(Iterable as) { + public Iterable checkedApply(Iterable as) { return new DistinctIterable<>(as); } @SuppressWarnings("unchecked") public static Distinct distinct() { - return INSTANCE; + return (Distinct) INSTANCE; } public static Iterable distinct(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Downcast.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Downcast.java new file mode 100644 index 000000000..d9c0c3985 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Downcast.java @@ -0,0 +1,32 @@ +package com.jnape.palatable.lambda.functions.builtin.fn1; + +import com.jnape.palatable.lambda.functions.Fn1; + +/** + * Covariantly cast a value of type B to a value of subtype A. Unsafe. + * + * @param the subtype + * @param the supertype + */ +public final class Downcast implements Fn1 { + + private static final Downcast INSTANCE = new Downcast<>(); + + private Downcast() { + } + + @Override + @SuppressWarnings("unchecked") + public A checkedApply(B b) { + return (A) b; + } + + @SuppressWarnings("unchecked") + public static Downcast downcast() { + return (Downcast) INSTANCE; + } + + public static A downcast(B b) { + return Downcast.downcast().apply(b); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Empty.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Empty.java index 9906aa803..6ea6e6254 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Empty.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Empty.java @@ -9,22 +9,22 @@ */ public final class Empty implements Predicate> { - private static final Empty INSTANCE = new Empty(); + private static final Empty INSTANCE = new Empty<>(); private Empty() { } @Override - public Boolean apply(Iterable as) { + public Boolean checkedApply(Iterable as) { return !as.iterator().hasNext(); } @SuppressWarnings("unchecked") public static Empty empty() { - return INSTANCE; + return (Empty) INSTANCE; } public static Boolean empty(Iterable as) { - return Empty.empty().test(as); + return Empty.empty().apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Flatten.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Flatten.java index 4c88bdec8..812452965 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Flatten.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Flatten.java @@ -1,7 +1,7 @@ package com.jnape.palatable.lambda.functions.builtin.fn1; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.iteration.FlatteningIterator; +import com.jnape.palatable.lambda.internal.iteration.FlatteningIterator; /** * Given a nested {@link Iterable} of {@link Iterable}s, return a lazily flattening {@link Iterable} @@ -10,19 +10,19 @@ * @param the nested Iterable element type */ public final class Flatten implements Fn1>, Iterable> { - private static final Flatten INSTANCE = new Flatten(); + private static final Flatten INSTANCE = new Flatten<>(); private Flatten() { } @Override - public Iterable apply(Iterable> iterables) { + public Iterable checkedApply(Iterable> iterables) { return () -> new FlatteningIterator<>(iterables.iterator()); } @SuppressWarnings("unchecked") public static Flatten flatten() { - return INSTANCE; + return (Flatten) INSTANCE; } public static Iterable flatten(Iterable> as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Force.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Force.java index 511b90b4e..a198fc9ff 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Force.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Force.java @@ -10,14 +10,14 @@ */ public final class Force implements Fn1, Iterable> { - private static final Force INSTANCE = new Force(); + private static final Force INSTANCE = new Force<>(); private Force() { } @Override @SuppressWarnings("StatementWithEmptyBody") - public Iterable apply(Iterable as) { + public Iterable checkedApply(Iterable as) { for (A ignored : as) { } return as; @@ -25,7 +25,7 @@ public Iterable apply(Iterable as) { @SuppressWarnings("unchecked") public static Force force() { - return INSTANCE; + return (Force) INSTANCE; } public static Iterable force(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Head.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Head.java index e8abf632b..a7c2c16fd 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Head.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Head.java @@ -16,20 +16,20 @@ */ public final class Head implements Fn1, Maybe> { - private static final Head INSTANCE = new Head(); + private static final Head INSTANCE = new Head<>(); private Head() { } @Override - public Maybe apply(Iterable as) { + public Maybe checkedApply(Iterable as) { Iterator iterator = as.iterator(); return iterator.hasNext() ? just(iterator.next()) : nothing(); } @SuppressWarnings("unchecked") public static Head head() { - return INSTANCE; + return (Head) INSTANCE; } public static Maybe head(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Id.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Id.java index 640927f50..c2f8c06ee 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Id.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Id.java @@ -9,18 +9,18 @@ */ public final class Id implements Fn1 { - private static final Id INSTANCE = new Id(); + private static final Id INSTANCE = new Id<>(); private Id() { } @Override - public A apply(A a) { + public A checkedApply(A a) { return a; } @SuppressWarnings("unchecked") public static Id id() { - return INSTANCE; + return (Id) INSTANCE; } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Init.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Init.java index ced05d274..66cea88bf 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Init.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Init.java @@ -1,7 +1,7 @@ package com.jnape.palatable.lambda.functions.builtin.fn1; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.iteration.InitIterator; +import com.jnape.palatable.lambda.internal.iteration.InitIterator; /** * Given an {@link Iterable}<A>, produce an @@ -11,19 +11,19 @@ */ public final class Init implements Fn1, Iterable> { - private static final Init INSTANCE = new Init(); + private static final Init INSTANCE = new Init<>(); private Init() { } @Override - public Iterable apply(Iterable as) { + public Iterable checkedApply(Iterable as) { return () -> new InitIterator<>(as); } @SuppressWarnings("unchecked") public static Init init() { - return INSTANCE; + return (Init) INSTANCE; } public static Iterable init(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Inits.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Inits.java index 52c0413b6..846762200 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Inits.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Inits.java @@ -19,19 +19,19 @@ */ public final class Inits implements Fn1, Iterable>> { - private static final Inits INSTANCE = new Inits(); + private static final Inits INSTANCE = new Inits<>(); private Inits() { } @Override - public Iterable> apply(Iterable as) { - return scanLeft(Snoc.snoc().flip().toBiFunction(), Collections::emptyIterator, as); + public Iterable> checkedApply(Iterable as) { + return scanLeft(Snoc.snoc().flip(), Collections::emptyIterator, as); } @SuppressWarnings("unchecked") public static Inits inits() { - return INSTANCE; + return (Inits) INSTANCE; } public static Iterable> inits(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Last.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Last.java index 4710f7900..a71c1dda6 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Last.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Last.java @@ -13,13 +13,13 @@ */ public final class Last implements Fn1, Maybe> { - private static final Last INSTANCE = new Last(); + private static final Last INSTANCE = new Last<>(); private Last() { } @Override - public Maybe apply(Iterable as) { + public Maybe checkedApply(Iterable as) { A last = null; for (A a : as) { last = a; @@ -29,7 +29,7 @@ public Maybe apply(Iterable as) { @SuppressWarnings("unchecked") public static Last last() { - return INSTANCE; + return (Last) INSTANCE; } public static Maybe last(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Magnetize.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Magnetize.java index 47c4d3ed8..ce2d2e2a3 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Magnetize.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Magnetize.java @@ -12,19 +12,19 @@ */ public final class Magnetize implements Fn1, Iterable>> { - private static final Magnetize INSTANCE = new Magnetize(); + private static final Magnetize INSTANCE = new Magnetize<>(); private Magnetize() { } @Override - public Iterable> apply(Iterable as) { - return magnetizeBy(eq().toBiFunction(), as); + public Iterable> checkedApply(Iterable as) { + return magnetizeBy(eq(), as); } @SuppressWarnings("unchecked") public static Magnetize magnetize() { - return INSTANCE; + return (Magnetize) INSTANCE; } public static Iterable> magnetize(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Not.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Not.java index 5f0bb8691..e148fadcb 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Not.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Not.java @@ -1,36 +1,35 @@ package com.jnape.palatable.lambda.functions.builtin.fn1; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.specialized.BiPredicate; import com.jnape.palatable.lambda.functions.specialized.Predicate; -import java.util.function.Function; - /** * Negate a predicate function. * * @param the input argument type */ -public final class Not implements BiPredicate, A> { - private static final Not INSTANCE = new Not(); +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 checkedApply(Fn1 pred, A a) { return !pred.apply(a); } @SuppressWarnings("unchecked") public static Not not() { - return INSTANCE; + return (Not) INSTANCE; } - public static Predicate not(Function pred) { + public static Predicate not(Fn1 pred) { return Not.not().apply(pred); } - public static Boolean not(Function pred, A a) { + public static Boolean not(Fn1 pred, A a) { return not(pred).apply(a); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Occurrences.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Occurrences.java index 8a9062942..6fea549c8 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Occurrences.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Occurrences.java @@ -14,13 +14,13 @@ * @param the {@link Iterable} element type */ public final class Occurrences implements Fn1, Map> { - private static final Occurrences INSTANCE = new Occurrences(); + private static final Occurrences INSTANCE = new Occurrences<>(); private Occurrences() { } @Override - public Map apply(Iterable as) { + public Map checkedApply(Iterable as) { return foldLeft((occurrences, a) -> { occurrences.put(a, occurrences.getOrDefault(a, 0L) + 1); return occurrences; @@ -29,7 +29,7 @@ public Map apply(Iterable as) { @SuppressWarnings("unchecked") public static Occurrences occurrences() { - return INSTANCE; + return (Occurrences) INSTANCE; } public static Map occurrences(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Repeat.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Repeat.java index 4286dbace..0c91253d7 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Repeat.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Repeat.java @@ -1,7 +1,7 @@ package com.jnape.palatable.lambda.functions.builtin.fn1; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.iteration.RepetitiousIterator; +import com.jnape.palatable.lambda.internal.iteration.RepetitiousIterator; /** * Given a value, return an infinite Iterable that repeatedly iterates that value. @@ -10,19 +10,19 @@ */ public final class Repeat implements Fn1> { - private static final Repeat INSTANCE = new Repeat(); + private static final Repeat INSTANCE = new Repeat<>(); private Repeat() { } @Override - public Iterable apply(A a) { + public Iterable checkedApply(A a) { return () -> new RepetitiousIterator<>(a); } @SuppressWarnings("unchecked") public static Repeat repeat() { - return INSTANCE; + return (Repeat) INSTANCE; } public static Iterable repeat(A a) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Reverse.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Reverse.java index 7b50cecbc..54cbc5263 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Reverse.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Reverse.java @@ -1,7 +1,7 @@ package com.jnape.palatable.lambda.functions.builtin.fn1; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.iteration.ReversingIterable; +import com.jnape.palatable.lambda.internal.iteration.ReversingIterable; /** * Given an Iterable, return a reversed representation of that Iterable. Note that reversing @@ -11,19 +11,19 @@ */ public final class Reverse implements Fn1, Iterable> { - private static final Reverse INSTANCE = new Reverse(); + private static final Reverse INSTANCE = new Reverse<>(); private Reverse() { } @Override - public Iterable apply(Iterable as) { + public Iterable checkedApply(Iterable as) { return new ReversingIterable<>(as); } @SuppressWarnings("unchecked") public static Reverse reverse() { - return INSTANCE; + return (Reverse) INSTANCE; } public static Iterable reverse(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Size.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Size.java index 95dca3f36..061636248 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Size.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Size.java @@ -12,7 +12,7 @@ private Size() { } @Override - public Long apply(Iterable iterable) { + public Long checkedApply(Iterable iterable) { if (iterable instanceof Collection) return (long) ((Collection) iterable).size(); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Sort.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Sort.java index 96fb7056d..da00cfaaf 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Sort.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Sort.java @@ -19,19 +19,19 @@ */ public final class Sort> implements Fn1, List> { - private static final Sort INSTANCE = new Sort(); + private static final Sort INSTANCE = new Sort<>(); private Sort() { } @Override - public List apply(Iterable as) { + public List checkedApply(Iterable as) { return sortBy(id(), as); } @SuppressWarnings("unchecked") public static > Sort sort() { - return INSTANCE; + return (Sort) INSTANCE; } public static > List sort(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Tail.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Tail.java index 8b954fe07..9f776ccf0 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Tail.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Tail.java @@ -12,19 +12,19 @@ */ public final class Tail implements Fn1, Iterable> { - private static final Tail INSTANCE = new Tail(); + private static final Tail INSTANCE = new Tail<>(); private Tail() { } @Override - public Iterable apply(Iterable as) { + public Iterable checkedApply(Iterable as) { return drop(1, as); } @SuppressWarnings("unchecked") public static Tail tail() { - return INSTANCE; + return (Tail) INSTANCE; } public static Iterable tail(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Tails.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Tails.java index cbdc65589..7179d1f31 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Tails.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Tails.java @@ -22,19 +22,19 @@ */ public final class Tails implements Fn1, Iterable>> { - private static final Tails INSTANCE = new Tails(); + private static final Tails INSTANCE = new Tails<>(); private Tails() { } @Override - public Iterable> apply(Iterable as) { + public Iterable> checkedApply(Iterable as) { return snoc(emptyList(), zipWith((a, __) -> a, unfoldr(k -> just(tuple(drop(k, as), k + 1)), 0), as)); } @SuppressWarnings("unchecked") public static Tails tails() { - return INSTANCE; + return (Tails) INSTANCE; } public static Iterable> tails(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Uncons.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Uncons.java index 7c6c807bf..dc27d9bb3 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Uncons.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Uncons.java @@ -16,19 +16,19 @@ */ public final class Uncons implements Fn1, Maybe>>> { - private static final Uncons INSTANCE = new Uncons(); + private static final Uncons INSTANCE = new Uncons<>(); private Uncons() { } @Override - public Maybe>> apply(Iterable as) { + public Maybe>> checkedApply(Iterable as) { return head(as).fmap(a -> tuple(a, tail(as))); } @SuppressWarnings("unchecked") public static Uncons uncons() { - return INSTANCE; + return (Uncons) INSTANCE; } public static Maybe>> uncons(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Upcast.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Upcast.java index 08f6fe519..f4f187021 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Upcast.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Upcast.java @@ -22,19 +22,19 @@ */ public final class Upcast implements Fn1 { - private static final Upcast INSTANCE = new Upcast<>(); + private static final Upcast INSTANCE = new Upcast<>(); private Upcast() { } @Override - public B apply(A a) { + public B checkedApply(A a) { return a; } @SuppressWarnings("unchecked") public static Upcast upcast() { - return INSTANCE; + return (Upcast) INSTANCE; } public static B upcast(A a) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/All.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/All.java index 2aeb00eca..26d76101f 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/All.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/All.java @@ -3,8 +3,6 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.specialized.BiPredicate; -import java.util.function.Function; - /** * Eagerly apply a predicate to each element in an Iterable, returning true if every element * satisfies the predicate, and false otherwise. This method short-circuits on the first false @@ -13,15 +11,15 @@ * @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(); + private static final All INSTANCE = new All<>(); private All() { } @Override - public Boolean apply(Function predicate, Iterable as) { + public Boolean checkedApply(Fn1 predicate, Iterable as) { for (A a : as) if (!predicate.apply(a)) return false; @@ -31,14 +29,14 @@ public Boolean apply(Function predicate, Iterable< @SuppressWarnings("unchecked") public static All all() { - return INSTANCE; + return (All) INSTANCE; } - public static Fn1, ? extends Boolean> all(Function predicate) { + public static Fn1, ? extends Boolean> all(Fn1 predicate) { return All.all().apply(predicate); } - public static Boolean all(Function predicate, Iterable as) { + public static Boolean all(Fn1 predicate, Iterable as) { return All.all(predicate).apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java index f51050eae..5eb0b2cc4 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java @@ -3,7 +3,7 @@ import com.jnape.palatable.lambda.functions.Effect; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; -import com.jnape.palatable.lambda.functions.IO; +import com.jnape.palatable.lambda.io.IO; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; @@ -15,19 +15,19 @@ */ public final class Alter implements Fn2, A, IO> { - private static final Alter INSTANCE = new Alter(); + private static final Alter INSTANCE = new Alter<>(); private Alter() { } @Override - public IO apply(Effect effect, A a) { + public IO checkedApply(Effect effect, A a) { return effect.fmap(io -> io.fmap(constantly(a))).apply(a); } @SuppressWarnings("unchecked") public static Alter alter() { - return INSTANCE; + return (Alter) INSTANCE; } public static Fn1> alter(Effect effect) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Any.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Any.java index 6285084f5..524b83159 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Any.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Any.java @@ -1,10 +1,9 @@ package com.jnape.palatable.lambda.functions.builtin.fn2; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.specialized.BiPredicate; import com.jnape.palatable.lambda.functions.specialized.Predicate; -import java.util.function.Function; - /** * Eagerly apply a predicate to each element in an Iterable, returning true if any element * satisfies the predicate, and false otherwise. This method short-circuits on the first true @@ -13,15 +12,15 @@ * @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(); + private static final Any INSTANCE = new Any<>(); private Any() { } @Override - public Boolean apply(Function predicate, Iterable as) { + public Boolean checkedApply(Fn1 predicate, Iterable as) { for (A a : as) if (predicate.apply(a)) return true; @@ -31,14 +30,14 @@ public Boolean apply(Function predicate, Iterable< @SuppressWarnings("unchecked") public static Any any() { - return INSTANCE; + return (Any) INSTANCE; } - public static Predicate> any(Function predicate) { + public static Predicate> any(Fn1 predicate) { return Any.any().apply(predicate); } - public static Boolean any(Function predicate, Iterable as) { + public static Boolean any(Fn1 predicate, Iterable as) { return Any.any(predicate).apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Both.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Both.java index 04bce60f5..0d22f7216 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Both.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Both.java @@ -4,8 +4,6 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn3; -import java.util.function.Function; - /** * Given two functions f and g, produce a * {@link Fn1}<A, {@link Tuple2}<B, C>> (the dual application of both functions). @@ -14,38 +12,33 @@ * @param the first function return type * @param the second function return type */ -public final class Both implements Fn3, Function, A, Tuple2> { +public final class Both implements + Fn3, Fn1, A, Tuple2> { - private static final Both INSTANCE = new Both(); + private static final Both INSTANCE = new Both<>(); private Both() { } @Override - public Tuple2 apply(Function f, - Function g, - A a) { - return Tuple2.fill(a).biMap(f, g); + public Tuple2 checkedApply(Fn1 f, Fn1 g, A a) { + return Tuple2.fill(a).biMap(f::apply, g::apply); } @SuppressWarnings("unchecked") public static Both both() { - return INSTANCE; + return (Both) INSTANCE; } - public static Fn1, Fn1>> both( - Function f) { + public static Fn1, Fn1>> both(Fn1 f) { return Both.both().apply(f); } - public static Fn1> both(Function f, - Function g) { + public static Fn1> both(Fn1 f, Fn1 g) { return Both.both(f).apply(g); } - public static Tuple2 both(Function f, - Function g, - A a) { + public static Tuple2 both(Fn1 f, Fn1 g, A a) { return Both.both(f, g).apply(a); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CartesianProduct.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CartesianProduct.java index aa883f86c..17b5ca94b 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CartesianProduct.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CartesianProduct.java @@ -3,7 +3,7 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; -import com.jnape.palatable.lambda.iteration.CombinatorialIterator; +import com.jnape.palatable.lambda.internal.iteration.CombinatorialIterator; /** * Lazily compute the cartesian product of an Iterable<A> and Iterable<B>, @@ -21,19 +21,19 @@ */ public final class CartesianProduct implements Fn2, Iterable, Iterable>> { - private static final CartesianProduct INSTANCE = new CartesianProduct(); + private static final CartesianProduct INSTANCE = new CartesianProduct<>(); private CartesianProduct() { } @Override - public Iterable> apply(Iterable as, Iterable bs) { + public Iterable> checkedApply(Iterable as, Iterable bs) { return () -> new CombinatorialIterator<>(as.iterator(), bs.iterator()); } @SuppressWarnings("unchecked") public static CartesianProduct cartesianProduct() { - return INSTANCE; + return (CartesianProduct) INSTANCE; } public static Fn1, Iterable>> cartesianProduct(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CmpEq.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CmpEq.java index 132dec5c7..3a91ade4c 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CmpEq.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CmpEq.java @@ -18,19 +18,19 @@ */ public final class CmpEq> implements BiPredicate { - private static final CmpEq INSTANCE = new CmpEq(); + private static final CmpEq INSTANCE = new CmpEq<>(); private CmpEq() { } @Override - public Boolean apply(A x, A y) { + public Boolean checkedApply(A x, A y) { return cmpEqBy(id(), x, y); } @SuppressWarnings("unchecked") public static > CmpEq cmpEq() { - return INSTANCE; + return (CmpEq) INSTANCE; } public static > Predicate cmpEq(A x) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Cons.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Cons.java index bee418871..63dabbaf2 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Cons.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Cons.java @@ -2,7 +2,7 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; -import com.jnape.palatable.lambda.iteration.ConsingIterator; +import com.jnape.palatable.lambda.internal.iteration.ConsingIterator; /** * Prepend an element to an Iterable. @@ -11,13 +11,13 @@ */ public final class Cons implements Fn2, Iterable> { - private static final Cons INSTANCE = new Cons(); + private static final Cons INSTANCE = new Cons<>(); private Cons() { } @Override - public Iterable apply(A a, Iterable as) { + public Iterable checkedApply(A a, Iterable as) { return () -> new ConsingIterator<>(a, as); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Difference.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Difference.java index 777279597..38735673c 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Difference.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Difference.java @@ -23,13 +23,13 @@ */ public final class Difference implements Fn2, Iterable, Iterable> { - private static final Difference INSTANCE = new Difference(); + private static final Difference INSTANCE = new Difference<>(); private Difference() { } @Override - public Iterable apply(Iterable xs, Iterable ys) { + public Iterable checkedApply(Iterable xs, Iterable ys) { return () -> { if (empty(xs)) return xs.iterator(); @@ -45,7 +45,7 @@ public Iterable apply(Iterable xs, Iterable ys) { @SuppressWarnings("unchecked") public static Difference difference() { - return INSTANCE; + return (Difference) INSTANCE; } public static Fn1, Iterable> difference(Iterable xs) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Drop.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Drop.java index c286d2da6..7229e51e9 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Drop.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Drop.java @@ -2,7 +2,7 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; -import com.jnape.palatable.lambda.iteration.DroppingIterable; +import com.jnape.palatable.lambda.internal.iteration.DroppingIterable; /** * Lazily skip the first n elements from an Iterable by returning an Iterable @@ -15,19 +15,19 @@ */ public final class Drop implements Fn2, Iterable> { - private static final Drop INSTANCE = new Drop(); + private static final Drop INSTANCE = new Drop<>(); private Drop() { } @Override - public Iterable apply(Integer n, Iterable as) { + public Iterable checkedApply(Integer n, Iterable as) { return new DroppingIterable<>(n, as); } @SuppressWarnings("unchecked") public static Drop drop() { - return INSTANCE; + return (Drop) INSTANCE; } public static Fn1, Iterable> drop(int n) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhile.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhile.java index 560f35c5c..a39ff3942 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhile.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhile.java @@ -2,9 +2,7 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; -import com.jnape.palatable.lambda.iteration.PredicatedDroppingIterable; - -import java.util.function.Function; +import com.jnape.palatable.lambda.internal.iteration.PredicatedDroppingIterable; /** * Lazily limit the Iterable by skipping the first contiguous group of elements that satisfy the predicate, @@ -16,28 +14,28 @@ * @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(); + private static final DropWhile INSTANCE = new DropWhile<>(); private DropWhile() { } @Override - public Iterable apply(Function predicate, Iterable as) { + public Iterable checkedApply(Fn1 predicate, Iterable as) { return new PredicatedDroppingIterable<>(predicate, as); } @SuppressWarnings("unchecked") public static DropWhile dropWhile() { - return INSTANCE; + return (DropWhile) INSTANCE; } - public static Fn1, Iterable> dropWhile(Function predicate) { + public static Fn1, Iterable> dropWhile(Fn1 predicate) { return DropWhile.dropWhile().apply(predicate); } - public static Iterable dropWhile(Function predicate, Iterable as) { + public static Iterable dropWhile(Fn1 predicate, Iterable as) { return DropWhile.dropWhile(predicate).apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Eq.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Eq.java index 83cce842c..e4c5aeda1 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Eq.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Eq.java @@ -10,19 +10,19 @@ */ public final class Eq implements BiPredicate { - private static final Eq INSTANCE = new Eq(); + private static final Eq INSTANCE = new Eq<>(); private Eq() { } @Override - public Boolean apply(A x, A y) { + public Boolean checkedApply(A x, A y) { return x == null ? y == null : x.equals(y); } @SuppressWarnings("unchecked") public static Eq eq() { - return INSTANCE; + return (Eq) INSTANCE; } public static Predicate eq(A x) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Filter.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Filter.java index fd0c70e7a..2b445ca11 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Filter.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Filter.java @@ -2,9 +2,7 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; -import com.jnape.palatable.lambda.iteration.FilteringIterable; - -import java.util.function.Function; +import com.jnape.palatable.lambda.internal.iteration.FilteringIterable; /** * Lazily apply a predicate to each element in an Iterable, returning an Iterable of just the @@ -14,28 +12,28 @@ * @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(); + private static final Filter INSTANCE = new Filter<>(); private Filter() { } @Override - public Iterable apply(Function predicate, Iterable as) { + public Iterable checkedApply(Fn1 predicate, Iterable as) { return new FilteringIterable<>(predicate, as); } @SuppressWarnings("unchecked") public static Filter filter() { - return INSTANCE; + return (Filter) INSTANCE; } - public static Fn1, Iterable> filter(Function predicate) { + public static Fn1, Iterable> filter(Fn1 predicate) { return Filter.filter().apply(predicate); } - public static Iterable filter(Function predicate, Iterable as) { + public static Iterable filter(Fn1 predicate, Iterable as) { return Filter.filter(predicate).apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Find.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Find.java index 716a4f3e8..0bb5c4e6b 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Find.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Find.java @@ -4,8 +4,6 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn1.Head.head; import static com.jnape.palatable.lambda.functions.builtin.fn1.Not.not; import static com.jnape.palatable.lambda.functions.builtin.fn2.DropWhile.dropWhile; @@ -18,28 +16,28 @@ * * @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(); + private static final Find INSTANCE = new Find<>(); private Find() { } @Override - public Maybe apply(Function predicate, Iterable as) { + public Maybe checkedApply(Fn1 predicate, Iterable as) { return head(dropWhile(not(predicate), as)); } @SuppressWarnings("unchecked") public static Find find() { - return INSTANCE; + return (Find) INSTANCE; } - public static Fn1, Maybe> find(Function predicate) { + public static Fn1, Maybe> find(Fn1 predicate) { return Find.find().apply(predicate); } - public static Maybe find(Function predicate, Iterable as) { + public static Maybe find(Fn1 predicate, Iterable as) { return Find.find(predicate).apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GT.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GT.java index 3c45e24cd..09d1be4ae 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GT.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GT.java @@ -8,8 +8,8 @@ import static com.jnape.palatable.lambda.functions.builtin.fn3.GTBy.gtBy; /** - * Given two {@link Comparable} values of type A, return true if the first value is strictly - * greater than the second value; otherwise, return false. + * Given two {@link Comparable} values of type A, return true if the second value is strictly + * greater than the first value; otherwise, return false. * * @param the value type * @see GTBy @@ -17,19 +17,19 @@ */ public final class GT> implements BiPredicate { - private static final GT INSTANCE = new GT(); + private static final GT INSTANCE = new GT<>(); private GT() { } @Override - public Boolean apply(A y, A x) { + public Boolean checkedApply(A y, A x) { return gtBy(id(), y, x); } @SuppressWarnings("unchecked") public static > GT gt() { - return INSTANCE; + return (GT) INSTANCE; } public static > Predicate gt(A y) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTE.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTE.java index 23069dd03..89413cea6 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTE.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTE.java @@ -8,8 +8,8 @@ import static com.jnape.palatable.lambda.functions.builtin.fn3.GTEBy.gteBy; /** - * Given two {@link Comparable} values of type A, return true if the first value is greater - * than or equal to the second value according to {@link Comparable#compareTo(Object)}; otherwise, return false. + * Given two {@link Comparable} values of type A, return true if the second value is greater + * than or equal to the first value according to {@link Comparable#compareTo(Object)}; otherwise, return false. * * @param the value type * @see GTEBy @@ -17,19 +17,19 @@ */ public final class GTE> implements BiPredicate { - private static final GTE INSTANCE = new GTE(); + private static final GTE INSTANCE = new GTE<>(); private GTE() { } @Override - public Boolean apply(A y, A x) { + public Boolean checkedApply(A y, A x) { return gteBy(id(), y, x); } @SuppressWarnings("unchecked") public static > GTE gte() { - return INSTANCE; + return (GTE) INSTANCE; } public static > Predicate gte(A y) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupBy.java index 1ef163a74..42e61912a 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupBy.java @@ -7,7 +7,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft; @@ -20,15 +19,15 @@ * @param the Map value type * @see InGroupsOf */ -public final class GroupBy implements Fn2, Iterable, Map>> { +public final class GroupBy implements Fn2, Iterable, Map>> { - private static final GroupBy INSTANCE = new GroupBy(); + private static final GroupBy INSTANCE = new GroupBy<>(); private GroupBy() { } @Override - public Map> apply(Function keyFn, Iterable vs) { + public Map> checkedApply(Fn1 keyFn, Iterable vs) { return foldLeft((m, v) -> { m.computeIfAbsent(keyFn.apply(v), __ -> new ArrayList<>()).add(v); return m; @@ -37,14 +36,14 @@ public Map> apply(Function keyFn, Iterable @SuppressWarnings("unchecked") public static GroupBy groupBy() { - return INSTANCE; + return (GroupBy) INSTANCE; } - public static Fn1, Map>> groupBy(Function keyFn) { + public static Fn1, Map>> groupBy(Fn1 keyFn) { return GroupBy.groupBy().apply(keyFn); } - public static Map> groupBy(Function keyFn, Iterable vs) { + public static Map> groupBy(Fn1 keyFn, Iterable vs) { return GroupBy.groupBy(keyFn).apply(vs); } } \ No newline at end of file diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/InGroupsOf.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/InGroupsOf.java index da93304c3..673d6c980 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/InGroupsOf.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/InGroupsOf.java @@ -2,7 +2,7 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; -import com.jnape.palatable.lambda.iteration.GroupingIterator; +import com.jnape.palatable.lambda.internal.iteration.GroupingIterator; /** * Lazily group the Iterable by returning an Iterable of smaller Iterables of @@ -14,19 +14,19 @@ */ public final class InGroupsOf implements Fn2, Iterable>> { - private static final InGroupsOf INSTANCE = new InGroupsOf(); + private static final InGroupsOf INSTANCE = new InGroupsOf<>(); private InGroupsOf() { } @Override - public Iterable> apply(Integer k, Iterable as) { + public Iterable> checkedApply(Integer k, Iterable as) { return () -> new GroupingIterator<>(k, as.iterator()); } @SuppressWarnings("unchecked") public static InGroupsOf inGroupsOf() { - return INSTANCE; + return (InGroupsOf) INSTANCE; } public static Fn1, Iterable>> inGroupsOf(Integer k) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersperse.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersperse.java index 68d7bc54d..4ff11cdec 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersperse.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersperse.java @@ -15,19 +15,19 @@ */ public final class Intersperse implements Fn2, Iterable> { - private static final Intersperse INSTANCE = new Intersperse(); + private static final Intersperse INSTANCE = new Intersperse<>(); private Intersperse() { } @Override - public Iterable apply(A a, Iterable as) { + public Iterable checkedApply(A a, Iterable as) { return tail(prependAll(a, as)); } @SuppressWarnings("unchecked") public static Intersperse intersperse() { - return INSTANCE; + return (Intersperse) INSTANCE; } public static Fn1, Iterable> intersperse(A a) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into.java index 5fa399bb1..523c08543 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into.java @@ -4,39 +4,38 @@ import com.jnape.palatable.lambda.functions.Fn2; import java.util.Map; -import java.util.function.BiFunction; /** - * Given a {@link BiFunction}<A, B, C> and a {@link Map.Entry}<A, B>, destructure - * the entry and apply the key and value as arguments to the function, returning the result. + * Given an {@link Fn2}<A, B, C> and a {@link Map.Entry}<A, B>, destructure the + * entry and apply the key and value as arguments to the function, returning the result. * * @param the first argument type * @param the second argument type * @param the result type */ -public final class Into implements Fn2, Map.Entry, C> { +public final class Into implements Fn2, Map.Entry, C> { - private static final Into INSTANCE = new Into(); + private static final Into INSTANCE = new Into<>(); private Into() { } @Override - public C apply(BiFunction fn, Map.Entry entry) { + public C checkedApply(Fn2 fn, Map.Entry entry) { return fn.apply(entry.getKey(), entry.getValue()); } @SuppressWarnings("unchecked") public static Into into() { - return INSTANCE; + return (Into) INSTANCE; } public static Fn1, C> into( - BiFunction fn) { + Fn2 fn) { return Into.into().apply(fn); } - public static C into(BiFunction fn, + public static C into(Fn2 fn, Map.Entry entry) { return Into.into(fn).apply(entry); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into1.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into1.java index e965ee544..3b574146b 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into1.java @@ -4,34 +4,32 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; -import java.util.function.Function; - /** - * Given a {@link Function}<A, B> and a {@link SingletonHList}<A>, - * pop the head and apply it to the function, returning the result. + * Given an {@link Fn1}<A, B> and a {@link SingletonHList}<A>, pop the head and + * apply it to the function, returning the result. * * @param the first argument type * @param the result type */ -public final class Into1 implements Fn2, SingletonHList, B> { +public final class Into1 implements Fn2, SingletonHList, B> { - private static final Into1 INSTANCE = new Into1(); + private static final Into1 INSTANCE = new Into1<>(); @Override - public B apply(Function fn, SingletonHList singletonHList) { + public B checkedApply(Fn1 fn, SingletonHList singletonHList) { return fn.apply(singletonHList.head()); } @SuppressWarnings("unchecked") public static Into1 into1() { - return INSTANCE; + return (Into1) INSTANCE; } - public static Fn1, B> into1(Function fn) { + public static Fn1, B> into1(Fn1 fn) { return Into1.into1().apply(fn); } - public static B into1(Function fn, SingletonHList singletonHList) { + public static B into1(Fn1 fn, SingletonHList singletonHList) { return Into1.into1(fn).apply(singletonHList); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into3.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into3.java index 9572d3f8d..d58969d57 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into3.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into3.java @@ -16,16 +16,16 @@ */ public final class Into3 implements Fn2, Product3, D> { - private static final Into3 INSTANCE = new Into3(); + private static final Into3 INSTANCE = new Into3<>(); @Override - public D apply(Fn3 fn, Product3 product) { - return product.into(fn); + public D checkedApply(Fn3 fn, Product3 product) { + return product.into(fn); } @SuppressWarnings("unchecked") public static Into3 into3() { - return INSTANCE; + return (Into3) INSTANCE; } public static Fn1, D> into3(Fn3 fn) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into4.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into4.java index 9cd0f37e0..14dba6f90 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into4.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into4.java @@ -17,16 +17,17 @@ */ public final class Into4 implements Fn2, Product4, E> { - private static final Into4 INSTANCE = new Into4(); + private static final Into4 INSTANCE = new Into4<>(); @Override - public E apply(Fn4 fn, Product4 product) { + public E checkedApply(Fn4 fn, + Product4 product) { return product.into(fn); } @SuppressWarnings("unchecked") public static Into4 into4() { - return INSTANCE; + return (Into4) INSTANCE; } public static Fn1, E> into4( diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into5.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into5.java index a55294f10..8cbdf25f5 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into5.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into5.java @@ -18,17 +18,17 @@ */ public final class Into5 implements Fn2, Product5, F> { - private static final Into5 INSTANCE = new Into5(); + private static final Into5 INSTANCE = new Into5<>(); @Override - public F apply(Fn5 fn, - Product5 product) { + public F checkedApply(Fn5 fn, + Product5 product) { return product.into(fn); } @SuppressWarnings("unchecked") public static Into5 into5() { - return INSTANCE; + return (Into5) INSTANCE; } public static Fn1, F> into5( diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into6.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into6.java index 9caf25a5b..0c59771f2 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into6.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into6.java @@ -20,17 +20,17 @@ */ public final class Into6 implements Fn2, Product6, G> { - private static final Into6 INSTANCE = new Into6(); + private static final Into6 INSTANCE = new Into6<>(); @Override - public G apply(Fn6 fn, - Product6 product) { + public G checkedApply(Fn6 fn, + Product6 product) { return product.into(fn); } @SuppressWarnings("unchecked") public static Into6 into6() { - return INSTANCE; + return (Into6) INSTANCE; } public static Fn1, G> into6( diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into7.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into7.java index 3ea4d0ebd..612068814 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into7.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into7.java @@ -21,17 +21,18 @@ */ public final class Into7 implements Fn2, Product7, H> { - private static final Into7 INSTANCE = new Into7(); + private static final Into7 INSTANCE = new Into7<>(); @Override - public H apply(Fn7 fn, - Product7 product) { + public H checkedApply( + Fn7 fn, + Product7 product) { return product.into(fn); } @SuppressWarnings("unchecked") public static Into7 into7() { - return INSTANCE; + return (Into7) INSTANCE; } public static Fn1, H> into7( diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into8.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into8.java index a04d17660..fdad33a72 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into8.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into8.java @@ -22,10 +22,10 @@ */ public final class Into8 implements Fn2, Product8, I> { - private static final Into8 INSTANCE = new Into8(); + private static final Into8 INSTANCE = new Into8<>(); @Override - public I apply( + public I checkedApply( Fn8 fn, Product8 product) { return product.into(fn); @@ -33,7 +33,7 @@ public I apply( @SuppressWarnings("unchecked") public static Into8 into8() { - return INSTANCE; + return (Into8) INSTANCE; } public static Fn1, I> into8( diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Iterate.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Iterate.java index d948bb12f..19fba6f79 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Iterate.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Iterate.java @@ -3,41 +3,39 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static com.jnape.palatable.lambda.functions.builtin.fn2.Unfoldr.unfoldr; /** - * Lazily generate an infinite Iterable from the successive applications of the function first to the - * initial seed value, then to the result, and so on; i.e., the result of iterate(x -> x + 1, 0) would - * produce an infinite Iterable over the elements 0, 1, 2, 3, ... and so on. + * Lazily generate an infinite {@link Iterable} from the successive applications of the function first to the initial + * seed value, then to the result, and so on; i.e., the result of iterate(x -> x + 1, 0) would produce + * an infinite {@link Iterable} over the elements 0, 1, 2, 3, ... and so on. * * @param The Iterable element type */ -public final class Iterate implements Fn2, A, Iterable> { +public final class Iterate implements Fn2, A, Iterable> { - private static final Iterate INSTANCE = new Iterate(); + private static final Iterate INSTANCE = new Iterate<>(); private Iterate() { } @Override - public Iterable apply(Function fn, A seed) { + public Iterable checkedApply(Fn1 fn, A seed) { return unfoldr(a -> just(tuple(a, fn.apply(a))), seed); } @SuppressWarnings("unchecked") public static Iterate iterate() { - return INSTANCE; + return (Iterate) INSTANCE; } - public static Fn1> iterate(Function fn) { + public static Fn1> iterate(Fn1 fn) { return Iterate.iterate().apply(fn); } - public static Iterable iterate(Function fn, A seed) { + public static Iterable iterate(Fn1 fn, A seed) { return Iterate.iterate(fn).apply(seed); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LT.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LT.java index d6a1d6d99..359d59b66 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LT.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LT.java @@ -8,8 +8,8 @@ import static com.jnape.palatable.lambda.functions.builtin.fn3.LTBy.ltBy; /** - * Given two {@link Comparable} values of type A, return true if the first value is strictly - * less than the second value; otherwise, return false. + * Given two {@link Comparable} values of type A, return true if the second value is strictly + * less than the first value; otherwise, return false. * * @param the value type * @see LTBy @@ -17,19 +17,19 @@ */ public final class LT> implements BiPredicate { - private static final LT INSTANCE = new LT(); + private static final LT INSTANCE = new LT<>(); private LT() { } @Override - public Boolean apply(A y, A x) { + public Boolean checkedApply(A y, A x) { return ltBy(id(), y, x); } @SuppressWarnings("unchecked") public static > LT lt() { - return INSTANCE; + return (LT) INSTANCE; } public static > Predicate lt(A y) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java index 19d2424c4..85f07b61e 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java @@ -8,8 +8,8 @@ import static com.jnape.palatable.lambda.functions.builtin.fn3.LTEBy.lteBy; /** - * Given two {@link Comparable} values of type A, return true if the first value is less than - * or equal to the second value according to {@link Comparable#compareTo(Object)} otherwise, return false. + * Given two {@link Comparable} values of type A, return true if the second value is less than + * or equal to the first value according to {@link Comparable#compareTo(Object)} otherwise, return false. * * @param the value typ * @see LTEBy @@ -17,19 +17,19 @@ */ public final class LTE> implements BiPredicate { - private static final LTE INSTANCE = new LTE(); + private static final LTE INSTANCE = new LTE<>(); private LTE() { } @Override - public Boolean apply(A y, A x) { + public Boolean checkedApply(A y, A x) { return lteBy(id(), y, x); } @SuppressWarnings("unchecked") public static > LTE lte() { - return INSTANCE; + return (LTE) INSTANCE; } public static > Predicate lte(A y) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRec.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRec.java new file mode 100644 index 000000000..7ebb8fe6f --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRec.java @@ -0,0 +1,53 @@ +package com.jnape.palatable.lambda.functions.builtin.fn2; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functor.builtin.Lazy; + +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; +import static com.jnape.palatable.lambda.monad.Monad.join; + +/** + * Given a {@link Fn2} that receives a recursive function and an input and yields a {@link Lazy lazy} result, and an + * input, produce a {@link Lazy lazy} result that, when forced, will recursively invoke the function until it terminates + * in a stack-safe way. + *

+ * Example: + *

+ * {@code
+ * Lazy lazyFactorial = lazyRec((fact, x) -> x.equals(ONE)
+ *                                                       ? lazy(x)
+ *                                                       : fact.apply(x.subtract(ONE)).fmap(y -> y.multiply(x)),
+ *                                                  BigInteger.valueOf(50_000));
+ * BigInteger value = lazyFactorial.value(); // 3.34732050959714483691547609407148647791277322381045 x 10^213236
+ * }
+ * 
+ * + * @param the input type + * @param the output type + */ +public final class LazyRec implements Fn2>, A, Lazy>, A, Lazy> { + + private static final LazyRec INSTANCE = new LazyRec<>(); + + private LazyRec() { + } + + @Override + public Lazy checkedApply(Fn2>, A, Lazy> fn, A a) { + return join(lazy(() -> fn.apply(nextA -> apply(fn, nextA), a))); + } + + @SuppressWarnings("unchecked") + public static LazyRec lazyRec() { + return (LazyRec) INSTANCE; + } + + public static Fn1> lazyRec(Fn2>, A, Lazy> fn) { + return LazyRec.lazyRec().apply(fn); + } + + public static Lazy lazyRec(Fn2>, A, Lazy> fn, A a) { + return lazyRec(fn).apply(a); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/MagnetizeBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/MagnetizeBy.java index ef94c372a..43697b8a5 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/MagnetizeBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/MagnetizeBy.java @@ -4,7 +4,6 @@ import com.jnape.palatable.lambda.functions.Fn2; import java.util.Collections; -import java.util.function.BiFunction; import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; @@ -25,15 +24,16 @@ * * @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(); + private static final MagnetizeBy INSTANCE = new MagnetizeBy<>(); private MagnetizeBy() { } @Override - public Iterable> apply(BiFunction predicate, Iterable as) { + public Iterable> checkedApply(Fn2 predicate, + Iterable as) { return () -> uncons(as).fmap(into((A head, Iterable tail) -> { Iterable group = cons(head, unfoldr(into((pivot, ys) -> uncons(ys) .flatMap(into((y, recurse) -> predicate.apply(pivot, y) @@ -45,16 +45,16 @@ public Iterable> apply(BiFunction MagnetizeBy magnetizeBy() { - return INSTANCE; + return (MagnetizeBy) INSTANCE; } public static Fn1, Iterable>> magnetizeBy( - BiFunction predicate) { + Fn2 predicate) { return MagnetizeBy.magnetizeBy().apply(predicate); } public static Iterable> magnetizeBy( - BiFunction predicate, + Fn2 predicate, Iterable as) { return MagnetizeBy.magnetizeBy(predicate).apply(as); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Map.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Map.java index 2b48c2a07..ace10d667 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Map.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Map.java @@ -2,9 +2,7 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; -import com.jnape.palatable.lambda.iteration.MappingIterable; - -import java.util.function.Function; +import com.jnape.palatable.lambda.internal.iteration.MappingIterable; /** * Lazily apply a function to each element in an Iterable, producing an Iterable of the mapped @@ -13,28 +11,28 @@ * @param A type contravariant to the input Iterable element type * @param A type covariant to the output Iterable element type */ -public final class Map implements Fn2, Iterable, Iterable> { +public final class Map implements Fn2, Iterable, Iterable> { - private static final Map INSTANCE = new Map(); + private static final Map INSTANCE = new Map<>(); private Map() { } @Override - public Iterable apply(Function fn, Iterable as) { + public Iterable checkedApply(Fn1 fn, Iterable as) { return new MappingIterable<>(fn, as); } @SuppressWarnings("unchecked") public static Map map() { - return INSTANCE; + return (Map) INSTANCE; } - public static Fn1, Iterable> map(Function fn) { + public static Fn1, Iterable> map(Fn1 fn) { return Map.map().apply(fn); } - public static Iterable map(Function fn, Iterable as) { + public static Iterable map(Fn1 fn, Iterable as) { return Map.map(fn).apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial2.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial2.java deleted file mode 100644 index 2c2317470..000000000 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial2.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.jnape.palatable.lambda.functions.builtin.fn2; - -import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.Fn2; - -import java.util.function.BiFunction; - -/** - * Partially apply (fix) the first argument of a {@link BiFunction}, producing an Fn1 that - * takes the remaining argument. This is isomorphic to calling {@link Fn2#apply(Object)}. - * - * @param The type of the value to be supplied - * @param The input argument type of the resulting function - * @param The return type of the resulting function - * @see Partial3 - */ -public final class Partial2 implements Fn2, A, Fn1> { - - private static final Partial2 INSTANCE = new Partial2(); - - private Partial2() { - } - - @Override - public Fn1 apply(BiFunction fn, A a) { - return b -> fn.apply(a, b); - } - - @SuppressWarnings("unchecked") - public static Partial2, A, Fn1> partial2() { - return INSTANCE; - } - - public static Fn1> partial2(BiFunction fn) { - return Partial2.partial2().apply(new Partial2().toBiFunction(), fn); - } - - public static Fn1 partial2(BiFunction fn, A a) { - return partial2(fn).apply(a); - } -} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial3.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial3.java deleted file mode 100644 index 8473a356b..000000000 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial3.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.jnape.palatable.lambda.functions.builtin.fn2; - -import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.Fn2; -import com.jnape.palatable.lambda.functions.Fn3; - -/** - * Partially apply (fix) the first argument of a Fn3, producing a Fn2 that takes the remaining - * two argument. This is isomorphic to calling {@link Fn3#apply(Object)}. - * - * @param The type of the value to be supplied - * @param The first input argument type of the resulting function - * @param The second input argument type of the resulting function - * @param The return type of the resulting function - * @see Partial2 - */ -public final class Partial3 implements Fn2, A, Fn2> { - - private static final Partial3 INSTANCE = new Partial3(); - - private Partial3() { - } - - @Override - public Fn2 apply(Fn3 fn, A a) { - return fn.apply(a); - } - - @SuppressWarnings("unchecked") - public static Partial3 partial3() { - return INSTANCE; - } - - public static Fn1> partial3(Fn3 fn) { - return Partial3.partial3().apply(fn); - } - - public static Fn2 partial3(Fn3 fn, A a) { - return partial3(fn).apply(a); - } -} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partition.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partition.java index 5a9a17148..20efa316f 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partition.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partition.java @@ -6,7 +6,6 @@ import com.jnape.palatable.lambda.functions.Fn2; import java.util.Collections; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn1.Flatten.flatten; import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; @@ -24,16 +23,16 @@ * @param The output right Iterable element type, as well as the CoProduct2 B type * @see CoProduct2 */ -public final class Partition implements Fn2>, Iterable, Tuple2, Iterable>> { +public final class Partition implements Fn2>, Iterable, Tuple2, Iterable>> { - private static final Partition INSTANCE = new Partition(); + private static final Partition INSTANCE = new Partition<>(); private Partition() { } @Override - public Tuple2, Iterable> apply(Function> function, - Iterable as) { + public Tuple2, Iterable> checkedApply(Fn1> function, + Iterable as) { return Tuple2.>>fill(map(function, as)) .biMap(Map., Iterable>map(cp -> cp.match(Collections::singleton, __ -> emptySet())), Map., Iterable>map(cp -> cp.match(__ -> emptySet(), Collections::singleton))) @@ -42,16 +41,16 @@ public Tuple2, Iterable> apply(Function Partition partition() { - return INSTANCE; + return (Partition) INSTANCE; } public static Fn1, Tuple2, Iterable>> partition( - Function> function) { + Fn1> function) { return Partition.partition().apply(function); } public static Tuple2, Iterable> partition( - Function> function, + Fn1> function, Iterable as) { return Partition.partition(function).apply(as); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek.java index 59ee59cda..bea6bb1c5 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek.java @@ -1,44 +1,43 @@ package com.jnape.palatable.lambda.functions.builtin.fn2; +import com.jnape.palatable.lambda.functions.Effect; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functor.Functor; - -import java.util.function.Consumer; -import java.util.function.Function; +import com.jnape.palatable.lambda.io.IO; /** - * Given a {@link Consumer}, "peek" at the value contained inside a {@link Functor} via - * {@link Functor#fmap(Function)}, applying the {@link Consumer} to the contained value, if there is one. + * Given an {@link Effect}, "peek" at the value contained inside a {@link Functor} via {@link Functor#fmap(Fn1)}, + * applying the {@link Effect} to the contained value, if there is one. * * @param the functor parameter type * @param the functor type */ -public final class Peek> implements Fn2, FA, FA> { - private static final Peek INSTANCE = new Peek<>(); +public final class Peek> implements Fn2>, FA, FA> { + private static final Peek INSTANCE = new Peek<>(); private Peek() { } @Override @SuppressWarnings("unchecked") - public FA apply(Consumer consumer, FA fa) { + public FA checkedApply(Fn1> effect, FA fa) { return (FA) fa.fmap(a -> { - consumer.accept(a); + effect.apply(a).unsafePerformIO(); return a; - }); + }).coerce(); } @SuppressWarnings("unchecked") public static > Peek peek() { - return INSTANCE; + return (Peek) INSTANCE; } - public static > Fn1 peek(Consumer consumer) { - return Peek.peek().apply(consumer); + public static > Fn1 peek(Fn1> effect) { + return Peek.peek().apply(effect); } - public static > FA peek(Consumer consumer, FA fa) { - return Peek.peek(consumer).apply(fa); + public static > FA peek(Fn1> effect, FA fa) { + return Peek.peek(effect).apply(fa); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2.java index d544ac7d7..3114f26c1 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2.java @@ -1,61 +1,60 @@ package com.jnape.palatable.lambda.functions.builtin.fn2; +import com.jnape.palatable.lambda.functions.Effect; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.Fn3; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.BoundedBifunctor; - -import java.util.function.Consumer; -import java.util.function.Function; +import com.jnape.palatable.lambda.io.IO; /** - * Given two {@link Consumer}s, "peek" at the values contained inside a {@link Bifunctor} via - * {@link Bifunctor#biMap(Function, Function)}, applying the {@link Consumer}s to the contained values, - * if there are any. + * Given two {@link Effect}s, "peek" at the values contained inside a {@link Bifunctor} via + * {@link BoundedBifunctor#biMap(Fn1, Fn1)}, applying the {@link Effect}s to the contained values, if there are any. * * @param the bifunctor's first parameter type * @param the bifunctor's second parameter type * @param the bifunctor type */ -public final class Peek2> implements Fn3, Consumer, FAB, FAB> { - private static final Peek2 INSTANCE = new Peek2<>(); +public final class Peek2> implements + Fn3>, Fn1>, FAB, FAB> { + private static final Peek2 INSTANCE = new Peek2<>(); private Peek2() { } @Override @SuppressWarnings("unchecked") - public FAB apply(Consumer aConsumer, Consumer bConsumer, FAB fab) { + public FAB checkedApply(Fn1> effectA, Fn1> effectB, FAB fab) { return (FAB) fab.biMap(a -> { - aConsumer.accept(a); + effectA.apply(a).unsafePerformIO(); return a; }, b -> { - bConsumer.accept(b); + effectB.apply(b).unsafePerformIO(); return b; }); } @SuppressWarnings("unchecked") public static > Peek2 peek2() { - return INSTANCE; + return (Peek2) INSTANCE; } - public static > Fn2, FAB, FAB> peek2( - Consumer aConsumer) { - return Peek2.peek2().apply(aConsumer); + public static > + Fn2>, FAB, FAB> peek2(Fn1> effectA) { + return Peek2.peek2().apply(effectA); } public static > Fn1 peek2( - Consumer aConsumer, - Consumer bConsumer) { - return Peek2.peek2(aConsumer).apply(bConsumer); + Fn1> effectA, + Fn1> effectB) { + return Peek2.peek2(effectA).apply(effectB); } public static > FAB peek2( - Consumer aConsumer, - Consumer bConsumer, + Fn1> effectA, + Fn1> effectB, FAB fab) { - return Peek2.peek2(aConsumer, bConsumer).apply(fab); + return Peek2.peek2(effectA, effectB).apply(fab); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/PrependAll.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/PrependAll.java index 4c7f26f2a..ad25f29f7 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/PrependAll.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/PrependAll.java @@ -2,7 +2,7 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; -import com.jnape.palatable.lambda.iteration.PrependingIterator; +import com.jnape.palatable.lambda.internal.iteration.PrependingIterator; /** * Lazily prepend each value with of the Iterable with the supplied separator value. An empty @@ -13,19 +13,19 @@ */ public final class PrependAll implements Fn2, Iterable> { - private static final PrependAll INSTANCE = new PrependAll(); + private static final PrependAll INSTANCE = new PrependAll<>(); private PrependAll() { } @Override - public Iterable apply(A a, Iterable as) { + public Iterable checkedApply(A a, Iterable as) { return () -> new PrependingIterator<>(a, as.iterator()); } @SuppressWarnings("unchecked") public static PrependAll prependAll() { - return INSTANCE; + return (PrependAll) INSTANCE; } public static Fn1, Iterable> prependAll(A a) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceLeft.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceLeft.java index c25b988a4..aae71023f 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceLeft.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceLeft.java @@ -6,14 +6,13 @@ import com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft; import java.util.Iterator; -import java.util.function.BiFunction; import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft; /** - * Given an {@link Iterable}<A> and a {@link BiFunction}<A, A, A>, iteratively + * Given an {@link Iterable}<A> and a {@link Fn2}<A, A, A>, iteratively * accumulate over the {@link Iterable}, returning {@link Maybe}<A>. If the {@link Iterable} is * empty, the result is {@link Maybe#nothing()}; otherwise, the result is wrapped in {@link Maybe#just}. For this * reason, null accumulation results are considered erroneous and will throw. @@ -25,29 +24,29 @@ * @see ReduceRight * @see FoldLeft */ -public final class ReduceLeft implements Fn2, Iterable, Maybe> { +public final class ReduceLeft implements Fn2, Iterable, Maybe> { - private static final ReduceLeft INSTANCE = new ReduceLeft(); + private static final ReduceLeft INSTANCE = new ReduceLeft<>(); private ReduceLeft() { } @Override - public Maybe apply(BiFunction fn, Iterable as) { + public Maybe checkedApply(Fn2 fn, Iterable as) { Iterator iterator = as.iterator(); return !iterator.hasNext() ? nothing() : just(foldLeft(fn, iterator.next(), () -> iterator)); } @SuppressWarnings("unchecked") public static ReduceLeft reduceLeft() { - return INSTANCE; + return (ReduceLeft) INSTANCE; } - public static Fn1, Maybe> reduceLeft(BiFunction fn) { + public static Fn1, Maybe> reduceLeft(Fn2 fn) { return ReduceLeft.reduceLeft().apply(fn); } - public static Maybe reduceLeft(BiFunction fn, Iterable as) { + public static Maybe reduceLeft(Fn2 fn, Iterable as) { return ReduceLeft.reduceLeft(fn).apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceRight.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceRight.java index 432ac0f56..6d027c594 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceRight.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceRight.java @@ -5,13 +5,11 @@ import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.builtin.fn3.FoldRight; -import java.util.function.BiFunction; - import static com.jnape.palatable.lambda.functions.builtin.fn1.Reverse.reverse; import static com.jnape.palatable.lambda.functions.builtin.fn2.ReduceLeft.reduceLeft; /** - * Given an {@link Iterable}<A> and a {@link BiFunction}<A, A, A>, iteratively + * Given an {@link Iterable}<A> and a {@link Fn2}<A, A, A>, iteratively * accumulate over the {@link Iterable}, returning {@link Maybe}<A>. If the {@link Iterable} is * empty, the result is {@link Maybe#nothing()}; otherwise, the result is wrapped in {@link Maybe#just}. For this * reason, null accumulation results are considered erroneous and will throw. @@ -23,28 +21,28 @@ * @see ReduceLeft * @see FoldRight */ -public final class ReduceRight implements Fn2, Iterable, Maybe> { +public final class ReduceRight implements Fn2, Iterable, Maybe> { - private static final ReduceRight INSTANCE = new ReduceRight(); + private static final ReduceRight INSTANCE = new ReduceRight<>(); private ReduceRight() { } @Override - public final Maybe apply(BiFunction fn, Iterable as) { + public final Maybe checkedApply(Fn2 fn, Iterable as) { return reduceLeft((b, a) -> fn.apply(a, b), reverse(as)); } @SuppressWarnings("unchecked") public static ReduceRight reduceRight() { - return INSTANCE; + return (ReduceRight) INSTANCE; } - public static Fn1, Maybe> reduceRight(BiFunction fn) { + public static Fn1, Maybe> reduceRight(Fn2 fn) { return ReduceRight.reduceRight().apply(fn); } - public static Maybe reduceRight(BiFunction fn, Iterable as) { + public static Maybe reduceRight(Fn2 fn, Iterable as) { return ReduceRight.reduceRight(fn).apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Replicate.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Replicate.java index d810f4938..98d436461 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Replicate.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Replicate.java @@ -13,19 +13,19 @@ */ public final class Replicate implements Fn2> { - private static final Replicate INSTANCE = new Replicate(); + private static final Replicate INSTANCE = new Replicate<>(); private Replicate() { } @Override - public Iterable apply(Integer n, A a) { + public Iterable checkedApply(Integer n, A a) { return take(n, repeat(a)); } @SuppressWarnings("unchecked") public static Replicate replicate() { - return INSTANCE; + return (Replicate) INSTANCE; } public static Fn1> replicate(Integer n) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Sequence.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Sequence.java index 36b394970..bed18e1aa 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Sequence.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Sequence.java @@ -8,7 +8,6 @@ import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Map; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; @@ -25,77 +24,72 @@ * @param the Traversable element type * @param the Applicative unification parameter * @param the Traversable unification parameter - * @param the Applicative instance wrapped in the input Traversable * @param the Traversable instance wrapped in the output Applicative * @param the concrete parametrized output Applicative type - * @param the concrete parametrized input Traversable type */ -public final class Sequence, +public final class Sequence, Trav extends Traversable, TravA extends Traversable, - AppTrav extends Applicative, - TravApp extends Traversable> implements Fn2, AppTrav> { + AppTrav extends Applicative> implements + Fn2, Trav>, Fn1, AppTrav> { - private static final Sequence INSTANCE = new Sequence(); + private static final Sequence INSTANCE = new Sequence<>(); private Sequence() { } @Override - public AppTrav apply(TravApp traversable, Function pure) { + public AppTrav checkedApply(Traversable, Trav> traversable, + Fn1 pure) { return traversable.traverse(id(), pure); } @SuppressWarnings("unchecked") - public static , + public static , Trav extends Traversable, TravA extends Traversable, - AppTrav extends Applicative, - TravApp extends Traversable> Sequence sequence() { - return INSTANCE; + AppTrav extends Applicative> Sequence sequence() { + return (Sequence) INSTANCE; } - public static , + public static , Trav extends Traversable, TravA extends Traversable, - AppTrav extends Applicative, - TravApp extends Traversable> Fn1, AppTrav> sequence( - TravApp traversable) { - return Sequence.sequence().apply(traversable); + AppTrav extends Applicative> Fn1, AppTrav> sequence( + Traversable, Trav> traversable) { + return Sequence.sequence().apply(traversable); } - public static , Trav extends Traversable, TravA extends Traversable, - AppA extends Applicative, - AppTrav extends Applicative, - TravApp extends Traversable> AppTrav sequence(TravApp traversable, - Function pure) { - return Sequence.sequence(traversable).apply(pure); + AppTrav extends Applicative> AppTrav sequence( + Traversable, Trav> traversable, + Fn1 pure) { + return Sequence.sequence(traversable).apply(pure); } @SuppressWarnings({"unchecked", "RedundantTypeArguments"}) - public static , AppIterable extends Applicative, App>, IterableApp extends Iterable> - Fn1, ? extends AppIterable>, AppIterable> sequence(IterableApp iterableApp) { - return pure -> (AppIterable) Sequence., AppA, Applicative, App>, LambdaIterable>sequence( + public static , AppIterable extends Applicative, App>> + Fn1, ? extends AppIterable>, AppIterable> sequence( + Iterable> iterableApp) { + return pure -> (AppIterable) Sequence., LambdaIterable, Applicative, App>>sequence( LambdaIterable.wrap(iterableApp), x -> pure.apply(x.unwrap()).fmap(LambdaIterable::wrap)) .fmap(LambdaIterable::unwrap); } - public static , AppIterable extends Applicative, App>, IterableApp extends Iterable> - AppIterable sequence(IterableApp iterableApp, Function, ? extends AppIterable> pure) { - return Sequence.sequence(iterableApp).apply(pure); + public static , AppIterable extends Applicative, App>> + AppIterable sequence(Iterable> iterableApp, + Fn1, ? extends AppIterable> pure) { + return Sequence.sequence(iterableApp).apply(pure); } @SuppressWarnings({"unchecked", "RedundantTypeArguments"}) - public static , AppMap extends Applicative, App>, MapApp extends Map> - Fn1, ? extends AppMap>, AppMap> sequence(MapApp mapApp) { - return pure -> (AppMap) Sequence., LambdaMap, AppB, Applicative, App>, LambdaMap>sequence( + public static , AppMap extends Applicative, App>> + Fn1, ? extends AppMap>, AppMap> sequence(Map> mapApp) { + return pure -> (AppMap) Sequence., LambdaMap, Applicative, App>>sequence( LambdaMap.wrap(mapApp), x -> pure.apply(x.unwrap()).fmap(LambdaMap::wrap)) .fmap(LambdaMap::unwrap); } - public static , AppMap extends Applicative, App>, MapApp extends Map> - AppMap sequence(MapApp mapApp, Function, ? extends AppMap> pure) { - return Sequence.sequence(mapApp).apply(pure); + public static , AppMap extends Applicative, App>> + AppMap sequence(Map> mapApp, Fn1, ? extends AppMap> pure) { + return Sequence.sequence(mapApp).apply(pure); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Slide.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Slide.java index 337d59788..1a65422d6 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Slide.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Slide.java @@ -21,13 +21,13 @@ */ public final class Slide implements Fn2, Iterable>> { - private static final Slide INSTANCE = new Slide<>(); + private static final Slide INSTANCE = new Slide<>(); private Slide() { } @Override - public Iterable> apply(Integer k, Iterable as) { + public Iterable> checkedApply(Integer k, Iterable as) { if (k == 0) throw new IllegalArgumentException("k must be greater than 0"); @@ -36,7 +36,7 @@ public Iterable> apply(Integer k, Iterable as) { @SuppressWarnings("unchecked") public static Slide slide() { - return INSTANCE; + return (Slide) INSTANCE; } public static Fn1, Iterable>> slide(Integer k) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Snoc.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Snoc.java index 6437c0c57..bfd8007bc 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Snoc.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Snoc.java @@ -2,7 +2,7 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; -import com.jnape.palatable.lambda.iteration.SnocIterable; +import com.jnape.palatable.lambda.internal.iteration.SnocIterable; /** * Opposite of {@link Cons}: lazily append an element to the end of the given {@link Iterable}. @@ -15,19 +15,19 @@ */ public final class Snoc implements Fn2, Iterable> { - private static final Snoc INSTANCE = new Snoc(); + private static final Snoc INSTANCE = new Snoc<>(); private Snoc() { } @Override - public Iterable apply(A a, Iterable as) { + public Iterable checkedApply(A a, Iterable as) { return new SnocIterable<>(a, as); } @SuppressWarnings("unchecked") public static Snoc snoc() { - return INSTANCE; + return (Snoc) INSTANCE; } public static Fn1, Iterable> snoc(A a) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortBy.java index b92628141..13ea9d0df 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortBy.java @@ -5,7 +5,6 @@ import com.jnape.palatable.lambda.functions.builtin.fn1.Sort; import java.util.List; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn2.SortWith.sortWith; import static java.util.Comparator.comparing; @@ -20,29 +19,28 @@ * @see Sort * @see SortWith */ -public final class SortBy> implements Fn2, Iterable, List> { +public final class SortBy> implements Fn2, Iterable, List> { - private static final SortBy INSTANCE = new SortBy(); + private static final SortBy INSTANCE = new SortBy<>(); private SortBy() { } @Override - public List apply(Function fn, Iterable as) { - return sortWith(comparing(fn), as); + public List checkedApply(Fn1 fn, Iterable as) { + return sortWith(comparing(fn.toFunction()), as); } @SuppressWarnings("unchecked") public static > SortBy sortBy() { - return INSTANCE; + return (SortBy) INSTANCE; } - public static > Fn1, List> sortBy( - Function fn) { + public static > Fn1, List> sortBy(Fn1 fn) { return SortBy.sortBy().apply(fn); } - public static > List sortBy(Function fn, Iterable as) { + public static > List sortBy(Fn1 fn, Iterable as) { return SortBy.sortBy(fn).apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortWith.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortWith.java index 813fb2e53..2c93239ee 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortWith.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortWith.java @@ -21,13 +21,13 @@ */ public final class SortWith implements Fn2, Iterable, List> { - private static final SortWith INSTANCE = new SortWith(); + private static final SortWith INSTANCE = new SortWith<>(); private SortWith() { } @Override - public List apply(Comparator comparator, Iterable as) { + public List checkedApply(Comparator comparator, Iterable as) { List result = toCollection(ArrayList::new, as); result.sort(comparator); return result; @@ -35,7 +35,7 @@ public List apply(Comparator comparator, Iterable as) { @SuppressWarnings("unchecked") public static SortWith sortWith() { - return INSTANCE; + return (SortWith) INSTANCE; } public static Fn1, List> sortWith(Comparator comparator) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Span.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Span.java index aea792d08..966b6518d 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Span.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Span.java @@ -4,8 +4,6 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn2.DropWhile.dropWhile; import static com.jnape.palatable.lambda.functions.builtin.fn2.TakeWhile.takeWhile; @@ -15,29 +13,30 @@ * * @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(); + private static final Span INSTANCE = new Span<>(); private Span() { } @Override - public Tuple2, Iterable> apply(Function predicate, Iterable as) { + public Tuple2, Iterable> checkedApply(Fn1 predicate, Iterable as) { return Tuple2.fill(as).biMap(takeWhile(predicate), dropWhile(predicate)); } @SuppressWarnings("unchecked") public static Span span() { - return INSTANCE; + return (Span) INSTANCE; } public static Fn1, Tuple2, Iterable>> span( - Function predicate) { + Fn1 predicate) { return Span.span().apply(predicate); } - public static Tuple2, Iterable> span(Function predicate, + public static Tuple2, Iterable> span(Fn1 predicate, Iterable as) { return Span.span(predicate).apply(as); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Take.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Take.java index ed10f75bc..15ddbcad2 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Take.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Take.java @@ -2,7 +2,7 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; -import com.jnape.palatable.lambda.iteration.TakingIterable; +import com.jnape.palatable.lambda.internal.iteration.TakingIterable; /** * Lazily limit the Iterable to n elements by returning an Iterable that stops @@ -15,19 +15,19 @@ */ public final class Take implements Fn2, Iterable> { - private static final Take INSTANCE = new Take(); + private static final Take INSTANCE = new Take<>(); private Take() { } @Override - public Iterable apply(Integer n, Iterable as) { + public Iterable checkedApply(Integer n, Iterable as) { return new TakingIterable<>(n, as); } @SuppressWarnings("unchecked") public static Take take() { - return INSTANCE; + return (Take) INSTANCE; } public static Fn1, Iterable> take(int n) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhile.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhile.java index 8285d953c..07524b7b4 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhile.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhile.java @@ -2,9 +2,7 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; -import com.jnape.palatable.lambda.iteration.PredicatedTakingIterable; - -import java.util.function.Function; +import com.jnape.palatable.lambda.internal.iteration.PredicatedTakingIterable; /** * Lazily limit the Iterable to the first group of contiguous elements that satisfy the predicate by @@ -15,28 +13,28 @@ * @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(); + private static final TakeWhile INSTANCE = new TakeWhile<>(); private TakeWhile() { } @Override - public Iterable apply(Function predicate, Iterable as) { + public Iterable checkedApply(Fn1 predicate, Iterable as) { return new PredicatedTakingIterable<>(predicate, as); } @SuppressWarnings("unchecked") public static TakeWhile takeWhile() { - return INSTANCE; + return (TakeWhile) INSTANCE; } - public static Fn1, Iterable> takeWhile(Function predicate) { + public static Fn1, Iterable> takeWhile(Fn1 predicate) { return TakeWhile.takeWhile().apply(predicate); } - public static Iterable takeWhile(Function predicate, Iterable as) { + public static Iterable takeWhile(Fn1 predicate, Iterable as) { return TakeWhile.takeWhile(predicate).apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToArray.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToArray.java index e12ae85b1..cecaa1543 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToArray.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToArray.java @@ -16,14 +16,14 @@ */ public final class ToArray implements Fn2, Iterable, A[]> { - private static final ToArray INSTANCE = new ToArray<>(); + private static final ToArray INSTANCE = new ToArray<>(); private ToArray() { } @Override @SuppressWarnings("unchecked") - public A[] apply(Class arrayType, Iterable as) { + public A[] checkedApply(Class arrayType, Iterable as) { A[] array = (A[]) Array.newInstance(arrayType.getComponentType(), size(as).intValue()); if (as instanceof Collection) return ((Collection) as).toArray(array); @@ -37,7 +37,7 @@ public A[] apply(Class arrayType, Iterable as) { @SuppressWarnings("unchecked") public static ToArray toArray() { - return INSTANCE; + return (ToArray) INSTANCE; } public static Fn1, A[]> toArray(Class arrayType) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToCollection.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToCollection.java index b9b46b893..535d90e0a 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToCollection.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToCollection.java @@ -1,43 +1,43 @@ package com.jnape.palatable.lambda.functions.builtin.fn2; +import com.jnape.palatable.lambda.functions.Fn0; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; import java.util.Collection; -import java.util.function.Supplier; /** - * Given a {@link Supplier} of some {@link Collection} C, create an instance of C and add - * all of the elements in the provided Iterable to the instance. Note that instances of C - * must support {@link Collection#add} (which is to say, must not throw on invocation). + * Given an {@link Fn0} of some {@link Collection} C, create an instance of C and add all of + * the elements in the provided Iterable to the instance. Note that instances of C must + * support {@link Collection#add} (which is to say, must not throw on invocation). * * @param the iterable element type * @param the resulting collection type */ -public final class ToCollection> implements Fn2, Iterable, C> { +public final class ToCollection> implements Fn2, Iterable, C> { - private static final ToCollection INSTANCE = new ToCollection(); + private static final ToCollection INSTANCE = new ToCollection<>(); private ToCollection() { } @Override - public C apply(Supplier cSupplier, Iterable as) { - C c = cSupplier.get(); + public C checkedApply(Fn0 cFn0, Iterable as) { + C c = cFn0.apply(); as.forEach(c::add); return c; } @SuppressWarnings("unchecked") public static > ToCollection toCollection() { - return INSTANCE; + return (ToCollection) INSTANCE; } - public static > Fn1, C> toCollection(Supplier cSupplier) { - return ToCollection.toCollection().apply(cSupplier); + public static > Fn1, C> toCollection(Fn0 cFn0) { + return ToCollection.toCollection().apply(cFn0); } - public static > C toCollection(Supplier cSupplier, Iterable as) { - return toCollection(cSupplier).apply(as); + public static > C toCollection(Fn0 cFn0, Iterable as) { + return toCollection(cFn0).apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToMap.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToMap.java index 1522720aa..85dad9e41 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToMap.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToMap.java @@ -1,48 +1,48 @@ package com.jnape.palatable.lambda.functions.builtin.fn2; +import com.jnape.palatable.lambda.functions.Fn0; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; import java.util.Map; -import java.util.function.Supplier; import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft; /** - * Given a {@link Supplier} of some {@link Map} M, create an instance of M and put - * all of the entries in the provided Iterable into the instance. Note that instances of M - * must support {@link java.util.Map#put} (which is to say, must not throw on invocation). + * Given an {@link Fn0} of some {@link Map} M, create an instance of M and put all of the + * entries in the provided Iterable into the instance. Note that instances of M must support + * {@link java.util.Map#put} (which is to say, must not throw on invocation). * * @param the key element type * @param the value element type * @param the resulting map type */ -public final class ToMap> implements Fn2, Iterable>, M> { +public final class ToMap> implements Fn2, Iterable>, M> { - private static final ToMap INSTANCE = new ToMap<>(); + private static final ToMap INSTANCE = new ToMap<>(); private ToMap() { } @Override - public M apply(Supplier mSupplier, Iterable> entries) { + public M checkedApply(Fn0 mFn0, Iterable> entries) { return foldLeft((m, kv) -> { m.put(kv.getKey(), kv.getValue()); return m; - }, mSupplier.get(), entries); + }, mFn0.apply(), entries); } @SuppressWarnings("unchecked") public static > ToMap toMap() { - return INSTANCE; + return (ToMap) INSTANCE; } - public static > Fn1>, M> toMap(Supplier mSupplier) { - return ToMap.toMap().apply(mSupplier); + public static > Fn1>, M> toMap(Fn0 mFn0) { + return ToMap.toMap().apply(mFn0); } - public static > M toMap(Supplier mSupplier, + public static > M toMap(Fn0 mFn0, Iterable> entries) { - return toMap(mSupplier).apply(entries); + return toMap(mFn0).apply(entries); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Tupler2.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Tupler2.java index de1b4a283..939518d38 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Tupler2.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Tupler2.java @@ -15,19 +15,19 @@ */ public final class Tupler2 implements Fn2> { - private static final Tupler2 INSTANCE = new Tupler2(); + private static final Tupler2 INSTANCE = new Tupler2<>(); private Tupler2() { } @Override - public Tuple2 apply(A a, B b) { + public Tuple2 checkedApply(A a, B b) { return tuple(a, b); } @SuppressWarnings("unchecked") public static Tupler2 tupler() { - return INSTANCE; + return (Tupler2) INSTANCE; } public static Fn1> tupler(A a) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Unfoldr.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Unfoldr.java index 9a2cd1b15..dbf8c8480 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Unfoldr.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Unfoldr.java @@ -4,9 +4,7 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; -import com.jnape.palatable.lambda.iteration.UnfoldingIterator; - -import java.util.function.Function; +import com.jnape.palatable.lambda.internal.iteration.UnfoldingIterator; /** * Given an initial seed value and a function that takes the seed type and produces an {@link Maybe}<{@link @@ -29,28 +27,28 @@ * @param The output Iterable element type * @param The unfolding function input type */ -public final class Unfoldr implements Fn2>>, B, Iterable> { +public final class Unfoldr implements Fn2>>, B, Iterable> { - private static final Unfoldr INSTANCE = new Unfoldr(); + private static final Unfoldr INSTANCE = new Unfoldr<>(); private Unfoldr() { } @Override - public Iterable apply(Function>> fn, B b) { + public Iterable checkedApply(Fn1>> fn, B b) { return () -> new UnfoldingIterator<>(fn, b); } @SuppressWarnings("unchecked") public static Unfoldr unfoldr() { - return INSTANCE; + return (Unfoldr) INSTANCE; } - public static Fn1> unfoldr(Function>> fn) { + public static Fn1> unfoldr(Fn1>> fn) { return Unfoldr.unfoldr().apply(fn); } - public static Iterable unfoldr(Function>> fn, B b) { + public static Iterable unfoldr(Fn1>> fn, B b) { return unfoldr(fn).apply(b); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Zip.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Zip.java index 323f00e02..ff41594b1 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Zip.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Zip.java @@ -4,6 +4,7 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Tupler2.tupler; import static com.jnape.palatable.lambda.functions.builtin.fn3.ZipWith.zipWith; /** @@ -17,19 +18,19 @@ */ public final class Zip implements Fn2, Iterable, Iterable>> { - private static final Zip INSTANCE = new Zip(); + private static final Zip INSTANCE = new Zip<>(); private Zip() { } @Override - public Iterable> apply(Iterable as, Iterable bs) { - return zipWith(Tupler2.tupler().toBiFunction(), as, bs); + public Iterable> checkedApply(Iterable as, Iterable bs) { + return zipWith(tupler(), as, bs); } @SuppressWarnings("unchecked") public static Zip zip() { - return INSTANCE; + return (Zip) INSTANCE; } public static Fn1, Iterable>> zip(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Between.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Between.java index 70dac2bce..ccb98929f 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Between.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Between.java @@ -14,19 +14,19 @@ */ public final class Between> implements Fn3 { - private static final Between INSTANCE = new Between<>(); + private static final Between INSTANCE = new Between<>(); private Between() { } @Override - public Boolean apply(A lower, A upper, A a) { + public Boolean checkedApply(A lower, A upper, A a) { return clamp(lower, upper, a).equals(a); } @SuppressWarnings("unchecked") public static > Between between() { - return INSTANCE; + return (Between) INSTANCE; } public static > BiPredicate between(A lower) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Bracket.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Bracket.java new file mode 100644 index 000000000..59e6f512d --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Bracket.java @@ -0,0 +1,52 @@ +package com.jnape.palatable.lambda.functions.builtin.fn3; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functions.Fn3; +import com.jnape.palatable.lambda.io.IO; +import com.jnape.palatable.lambda.monad.Monad; + +/** + * Given an {@link IO} that yields some type A, a cleanup operation to run if a value of that type could be + * provisioned, and a kleisli arrow from that type to a new {@link IO} of type B, produce an + * {@link IO}<B> that, when run, will provision the A, + * {@link Monad#flatMap(Fn1) flatMap} it to B, and clean up the original value if it was produced in the + * first place. + * + * @param the initial value to map and clean up + * @param the resulting type + */ +public final class Bracket implements + Fn3, Fn1>, Fn1>, IO> { + + private static final Bracket INSTANCE = new Bracket<>(); + + private Bracket() { + } + + @Override + public IO checkedApply(IO io, Fn1> cleanupIO, + Fn1> bodyIO) throws Throwable { + return io.flatMap(a -> bodyIO.apply(a).ensuring(cleanupIO.apply(a))); + } + + @SuppressWarnings("unchecked") + public static Bracket bracket() { + return (Bracket) INSTANCE; + } + + public static Fn2>, Fn1>, IO> bracket( + IO io) { + return Bracket.bracket().apply(io); + } + + public static Fn1>, IO> bracket( + IO io, Fn1> cleanupIO) { + return Bracket.bracket(io).apply(cleanupIO); + } + + public static IO bracket(IO io, Fn1> cleanupIO, + Fn1> bodyIO) { + return Bracket.bracket(io, cleanupIO).apply(bodyIO); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Clamp.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Clamp.java index 62d0c21de..3343afae4 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Clamp.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Clamp.java @@ -17,19 +17,19 @@ */ public final class Clamp> implements Fn3 { - private static final Clamp INSTANCE = new Clamp<>(); + private static final Clamp INSTANCE = new Clamp<>(); private Clamp() { } @Override - public A apply(A lower, A upper, A a) { + public A checkedApply(A lower, A upper, A a) { return max(min(lower, upper)).fmap(min(max(lower, upper))).apply(a); } @SuppressWarnings("unchecked") public static > Clamp clamp() { - return INSTANCE; + return (Clamp) INSTANCE; } public static > Fn2 clamp(A lower) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqBy.java index 156c51413..3b483aeaf 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqBy.java @@ -1,11 +1,12 @@ package com.jnape.palatable.lambda.functions.builtin.fn3; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn3; import com.jnape.palatable.lambda.functions.builtin.fn2.CmpEq; import com.jnape.palatable.lambda.functions.specialized.BiPredicate; import com.jnape.palatable.lambda.functions.specialized.Predicate; -import java.util.function.Function; +import static com.jnape.palatable.lambda.functions.specialized.Predicate.predicate; /** * Given a mapping function from some type A to some {@link Comparable} type B and two values @@ -18,42 +19,42 @@ * @see LTBy * @see GTBy */ -public final class CmpEqBy> implements Fn3, A, A, Boolean> { +public final class CmpEqBy> implements Fn3, A, A, Boolean> { - private static final CmpEqBy INSTANCE = new CmpEqBy(); + private static final CmpEqBy INSTANCE = new CmpEqBy<>(); private CmpEqBy() { } @Override - public Boolean apply(Function compareFn, A x, A y) { + public Boolean checkedApply(Fn1 compareFn, A x, A y) { return compareFn.apply(x).compareTo(compareFn.apply(y)) == 0; } @Override - public BiPredicate apply(Function compareFn) { + public BiPredicate apply(Fn1 compareFn) { return Fn3.super.apply(compareFn)::apply; } @Override - public Predicate apply(Function compareFn, A x) { - return Fn3.super.apply(compareFn, x)::apply; + public Predicate apply(Fn1 compareFn, A x) { + return predicate(Fn3.super.apply(compareFn, x)); } @SuppressWarnings("unchecked") public static > CmpEqBy cmpEqBy() { - return INSTANCE; + return (CmpEqBy) INSTANCE; } - public static > BiPredicate cmpEqBy(Function compareFn) { + public static > BiPredicate cmpEqBy(Fn1 compareFn) { return CmpEqBy.cmpEqBy().apply(compareFn); } - public static > Predicate cmpEqBy(Function compareFn, A x) { + public static > Predicate cmpEqBy(Fn1 compareFn, A x) { return CmpEqBy.cmpEqBy(compareFn).apply(x); } - public static > Boolean cmpEqBy(Function compareFn, A x, A y) { + public static > Boolean cmpEqBy(Fn1 compareFn, A x, A y) { return cmpEqBy(compareFn, x).apply(y); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldLeft.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldLeft.java index 17fb496d1..e05b1bcf0 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldLeft.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldLeft.java @@ -4,12 +4,10 @@ import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.Fn3; -import java.util.function.BiFunction; - /** - * Given an Iterable of As, a starting value B, and a {@link - * BiFunction}<B, A, B>, iteratively accumulate over the Iterable, ultimately returning a - * final B value. If the Iterable is empty, just return the starting B value. + * Given an Iterable of As, a starting value B, and a + * {@link Fn2}<B, A, B>, iteratively accumulate over the Iterable, ultimately returning + * a final B value. If the Iterable is empty, just return the starting B value. * Note that, as the name implies, this function accumulates from left to right, such that foldLeft(f, 0, * asList(1, 2, 3, 4, 5)) is evaluated as f(f(f(f(f(0, 1), 2), 3), 4), 5). *

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

+ * Example: + *

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

* For more information, read about Catamorphisms. @@ -23,32 +36,41 @@ * @param The accumulation type * @see FoldLeft */ -public final class FoldRight implements Fn3, B, Iterable, B> { +public final class FoldRight implements + Fn3, ? extends Lazy>, Lazy, Iterable, Lazy> { - private static final FoldRight INSTANCE = new FoldRight(); + private static final FoldRight INSTANCE = new FoldRight<>(); private FoldRight() { } @Override - public B apply(BiFunction fn, B acc, Iterable as) { - return foldLeft((b, a) -> fn.apply(a, b), acc, reverse(as)); + public Lazy checkedApply(Fn2, ? extends Lazy> fn, Lazy acc, + Iterable as) { + return lazyRec((f, lazyIt) -> lazyIt.flatMap(it -> it.hasNext() + ? fn.apply(it.next(), f.apply(lazy(it))) + : acc), + lazy(as::iterator)); } @SuppressWarnings("unchecked") public static FoldRight foldRight() { - return INSTANCE; + return (FoldRight) INSTANCE; } - public static Fn2, B> foldRight(BiFunction fn) { + public static Fn2, Iterable, Lazy> foldRight( + Fn2, ? extends Lazy> fn) { return FoldRight.foldRight().apply(fn); } - public static Fn1, B> foldRight(BiFunction fn, B acc) { + public static Fn1, Lazy> foldRight( + Fn2, ? extends Lazy> fn, + Lazy acc) { return FoldRight.foldRight(fn).apply(acc); } - public static B foldRight(BiFunction fn, B acc, Iterable as) { + public static Lazy foldRight(Fn2, ? extends Lazy> fn, Lazy acc, + Iterable as) { return FoldRight.foldRight(fn, acc).apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java index 4428784e1..cb9b45168 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java @@ -1,15 +1,16 @@ package com.jnape.palatable.lambda.functions.builtin.fn3; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn3; import com.jnape.palatable.lambda.functions.builtin.fn2.GT; import com.jnape.palatable.lambda.functions.specialized.BiPredicate; import com.jnape.palatable.lambda.functions.specialized.Predicate; -import java.util.function.Function; +import static com.jnape.palatable.lambda.functions.specialized.Predicate.predicate; /** * Given a mapping function from some type A to some {@link Comparable} type B and two values - * of type A, return true if the first value is strictly greater than the second value in + * of type A, return true if the second value is strictly greater than the first value in * terms of their mapped B results; otherwise, return false. * * @param the value type @@ -17,42 +18,42 @@ * @see GT * @see LTBy */ -public final class GTBy> implements Fn3, A, A, Boolean> { +public final class GTBy> implements Fn3, A, A, Boolean> { - private static final GTBy INSTANCE = new GTBy(); + private static final GTBy INSTANCE = new GTBy<>(); private GTBy() { } @Override - public Boolean apply(Function compareFn, A y, A x) { + public Boolean checkedApply(Fn1 compareFn, A y, A x) { return compareFn.apply(x).compareTo(compareFn.apply(y)) > 0; } @Override - public BiPredicate apply(Function compareFn) { + public BiPredicate apply(Fn1 compareFn) { return Fn3.super.apply(compareFn)::apply; } @Override - public Predicate apply(Function compareFn, A x) { - return Fn3.super.apply(compareFn, x)::apply; + public Predicate apply(Fn1 compareFn, A x) { + return predicate(Fn3.super.apply(compareFn, x)); } @SuppressWarnings("unchecked") public static > GTBy gtBy() { - return INSTANCE; + return (GTBy) INSTANCE; } - public static > BiPredicate gtBy(Function fn) { + public static > BiPredicate gtBy(Fn1 fn) { return GTBy.gtBy().apply(fn); } - public static > Predicate gtBy(Function fn, A y) { + public static > Predicate gtBy(Fn1 fn, A y) { return GTBy.gtBy(fn).apply(y); } - public static > Boolean gtBy(Function fn, A y, A x) { + public static > Boolean gtBy(Fn1 fn, A y, A x) { return gtBy(fn, y).apply(x); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java index 2c5d8ae26..30ef09852 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java @@ -1,17 +1,17 @@ package com.jnape.palatable.lambda.functions.builtin.fn3; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn3; import com.jnape.palatable.lambda.functions.builtin.fn2.GTE; import com.jnape.palatable.lambda.functions.specialized.BiPredicate; import com.jnape.palatable.lambda.functions.specialized.Predicate; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn3.CmpEqBy.cmpEqBy; +import static com.jnape.palatable.lambda.functions.specialized.Predicate.predicate; /** * Given a mapping function from some type A to some {@link Comparable} type B and two values - * of type A, return true if the first value is greater than or equal to the second value in + * of type A, return true if the second value is greater than or equal to the first value in * terms of their mapped B results according to {@link Comparable#compareTo(Object)}; otherwise, return * false. * @@ -20,42 +20,42 @@ * @see GTE * @see LTEBy */ -public final class GTEBy> implements Fn3, A, A, Boolean> { +public final class GTEBy> implements Fn3, A, A, Boolean> { - private static final GTEBy INSTANCE = new GTEBy(); + private static final GTEBy INSTANCE = new GTEBy<>(); private GTEBy() { } @Override - public Boolean apply(Function compareFn, A y, A x) { + public Boolean checkedApply(Fn1 compareFn, A y, A x) { return GTBy.gtBy(compareFn).or(cmpEqBy(compareFn)).apply(y, x); } @Override - public BiPredicate apply(Function compareFn) { + public BiPredicate apply(Fn1 compareFn) { return Fn3.super.apply(compareFn)::apply; } @Override - public Predicate apply(Function compareFn, A y) { - return Fn3.super.apply(compareFn, y)::apply; + public Predicate apply(Fn1 compareFn, A y) { + return predicate(Fn3.super.apply(compareFn, y)); } @SuppressWarnings("unchecked") public static > GTEBy gteBy() { - return INSTANCE; + return (GTEBy) INSTANCE; } - public static > BiPredicate gteBy(Function fn) { + public static > BiPredicate gteBy(Fn1 fn) { return GTEBy.gteBy().apply(fn); } - public static > Predicate gteBy(Function fn, A y) { + public static > Predicate gteBy(Fn1 fn, A y) { return GTEBy.gteBy(fn).apply(y); } - public static > Boolean gteBy(Function fn, A y, A x) { + public static > Boolean gteBy(Fn1 fn, A y, A x) { return gteBy(fn, y).apply(x); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java index 220a600e8..c442d9871 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java @@ -1,15 +1,16 @@ package com.jnape.palatable.lambda.functions.builtin.fn3; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn3; import com.jnape.palatable.lambda.functions.builtin.fn2.LT; import com.jnape.palatable.lambda.functions.specialized.BiPredicate; import com.jnape.palatable.lambda.functions.specialized.Predicate; -import java.util.function.Function; +import static com.jnape.palatable.lambda.functions.specialized.Predicate.predicate; /** * Given a mapping function from some type A to some {@link Comparable} type B and two values - * of type A, return true if the first value is strictly less than the second value in terms + * of type A, return true if the second value is strictly less than the first value in terms * of their mapped B results; otherwise, return false. * * @param the value type @@ -17,42 +18,42 @@ * @see LT * @see GTBy */ -public final class LTBy> implements Fn3, A, A, Boolean> { +public final class LTBy> implements Fn3, A, A, Boolean> { - private static final LTBy INSTANCE = new LTBy(); + private static final LTBy INSTANCE = new LTBy<>(); private LTBy() { } @Override - public Boolean apply(Function compareFn, A y, A x) { + public Boolean checkedApply(Fn1 compareFn, A y, A x) { return compareFn.apply(x).compareTo(compareFn.apply(y)) < 0; } @Override - public BiPredicate apply(Function compareFn) { + public BiPredicate apply(Fn1 compareFn) { return Fn3.super.apply(compareFn)::apply; } @Override - public Predicate apply(Function compareFn, A y) { - return Fn3.super.apply(compareFn, y)::apply; + public Predicate apply(Fn1 compareFn, A y) { + return predicate(Fn3.super.apply(compareFn, y)); } @SuppressWarnings("unchecked") public static > LTBy ltBy() { - return INSTANCE; + return (LTBy) INSTANCE; } - public static > BiPredicate ltBy(Function fn) { + public static > BiPredicate ltBy(Fn1 fn) { return LTBy.ltBy().apply(fn); } - public static > Predicate ltBy(Function fn, A y) { + public static > Predicate ltBy(Fn1 fn, A y) { return LTBy.ltBy(fn).apply(y); } - public static > Boolean ltBy(Function fn, A y, A x) { + public static > Boolean ltBy(Fn1 fn, A y, A x) { return ltBy(fn, y).apply(x); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java index a83fdc9c5..bc755470d 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java @@ -1,17 +1,16 @@ package com.jnape.palatable.lambda.functions.builtin.fn3; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn3; import com.jnape.palatable.lambda.functions.builtin.fn2.LTE; import com.jnape.palatable.lambda.functions.specialized.BiPredicate; import com.jnape.palatable.lambda.functions.specialized.Predicate; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn3.CmpEqBy.cmpEqBy; /** * Given a mapping function from some type A to some {@link Comparable} type B and two values - * of type A, return true if the first value is less than or equal to the second value in + * of type A, return true if the second value is less than or equal to the first value in * terms of their mapped B results according to {@link Comparable#compareTo(Object)}; otherwise, return * false. * @@ -20,42 +19,42 @@ * @see LTE * @see GTEBy */ -public final class LTEBy> implements Fn3, A, A, Boolean> { +public final class LTEBy> implements Fn3, A, A, Boolean> { - private static final LTEBy INSTANCE = new LTEBy(); + private static final LTEBy INSTANCE = new LTEBy<>(); private LTEBy() { } @Override - public Boolean apply(Function compareFn, A y, A x) { + public Boolean checkedApply(Fn1 compareFn, A y, A x) { return LTBy.ltBy(compareFn).or(cmpEqBy(compareFn)).apply(y, x); } @Override - public BiPredicate apply(Function compareFn) { + public BiPredicate apply(Fn1 compareFn) { return Fn3.super.apply(compareFn)::apply; } @Override - public Predicate apply(Function compareFn, A y) { + public Predicate apply(Fn1 compareFn, A y) { return Fn3.super.apply(compareFn, y)::apply; } @SuppressWarnings("unchecked") public static > LTEBy lteBy() { - return INSTANCE; + return (LTEBy) INSTANCE; } - public static > BiPredicate lteBy(Function fn) { + public static > BiPredicate lteBy(Fn1 fn) { return LTEBy.lteBy().apply(fn); } - public static > Predicate lteBy(Function fn, A y) { + public static > Predicate lteBy(Fn1 fn, A y) { return LTEBy.lteBy(fn).apply(y); } - public static > Boolean lteBy(Function fn, A y, A x) { + public static > Boolean lteBy(Fn1 fn, A y, A x) { return lteBy(fn, y).apply(x); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java index 7ba773691..e83048652 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java @@ -5,10 +5,8 @@ import com.jnape.palatable.lambda.functions.Fn3; import com.jnape.palatable.lambda.functor.Applicative; -import java.util.function.BiFunction; - /** - * Lift into and apply a {@link BiFunction} to two {@link Applicative} values, returning the result inside the same + * Lift into and apply an {@link Fn2} to two {@link Applicative} values, returning the result inside the same * {@link Applicative} context. Functionally equivalent to appB.zip(appA.fmap(fn)). * * @param the function's first argument type @@ -20,41 +18,48 @@ * @param the inferred applicative return type * @see Applicative#zip(Applicative) */ -public final class LiftA2, AppA extends Applicative, AppB extends Applicative, - AppC extends Applicative> implements Fn3, AppA, AppB, AppC> { + AppC extends Applicative> implements + Fn3, AppA, AppB, AppC> { - private static final LiftA2 INSTANCE = new LiftA2(); + private static final LiftA2 INSTANCE = new LiftA2<>(); private LiftA2() { } @Override - public AppC apply(BiFunction fn, AppA appA, AppB appB) { - return appB.zip(appA.fmap(Fn2.fn2(fn))).coerce(); + public AppC checkedApply(Fn2 fn, AppA appA, AppB appB) { + return appB.zip(appA.fmap(fn)).coerce(); } @SuppressWarnings("unchecked") - public static , AppB extends Applicative, AppC extends Applicative> LiftA2 liftA2() { - return INSTANCE; + public static , AppA extends Applicative, + AppB extends Applicative, + AppC extends Applicative> LiftA2 liftA2() { + return (LiftA2) INSTANCE; } - public static , AppB extends Applicative, AppC extends Applicative> Fn2 liftA2( - BiFunction fn) { + public static , AppA extends Applicative, + AppB extends Applicative, + AppC extends Applicative> Fn2 liftA2( + Fn2 fn) { return LiftA2.liftA2().apply(fn); } - public static , AppB extends Applicative, AppC extends Applicative> Fn1 liftA2( - BiFunction fn, - AppA appA) { + public static , AppA extends Applicative, + AppB extends Applicative, + AppC extends Applicative> Fn1 liftA2(Fn2 fn, + AppA appA) { return LiftA2.liftA2(fn).apply(appA); } - public static , AppB extends Applicative, AppC extends Applicative> AppC liftA2( - BiFunction fn, - AppA appA, - AppB appB) { + public static , AppA extends Applicative, + AppB extends Applicative, + AppC extends Applicative> AppC liftA2(Fn2 fn, + AppA appA, + AppB appB) { return LiftA2.liftA2(fn, appA).apply(appB); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ScanLeft.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ScanLeft.java index 9cc780a15..5db4f413a 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ScanLeft.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ScanLeft.java @@ -3,47 +3,46 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.Fn3; -import com.jnape.palatable.lambda.iteration.ScanningIterator; - -import java.util.function.BiFunction; +import com.jnape.palatable.lambda.internal.iteration.ScanningIterator; /** - * Given an Iterable of As, a starting value B, and a {@link - * BiFunction}<B, A, B>, iteratively accumulate over the Iterable, collecting each function - * application result, finally returning an Iterable of all the results. Note that, as the name implies, - * this function accumulates from left to right, such that scanLeft(f, 0, asList(1,2,3,4,5)) is evaluated - * as 0, f(0, 1), f(f(0, 1), 2), f(f(f(0, 1), 2), 3), f(f(f(f(0, 1), 2), 3), 4), f(f(f(f(f(0, 1), 2), 3), 4), 5). + * Given an Iterable of As, a starting value B, and a + * {@link Fn2}<B, A, B>, iteratively accumulate over the Iterable, collecting each + * function application result, finally returning an Iterable of all the results. Note that, as the name + * implies, this function accumulates from left to right, such that scanLeft(f, 0, asList(1,2,3,4,5)) is + * evaluated as 0, f(0, 1), f(f(0, 1), 2), f(f(f(0, 1), 2), 3), f(f(f(f(0, 1), 2), 3), 4), f(f(f(f(f(0, 1), 2), + * 3), 4), 5). * * @param The Iterable element type * @param The accumulation type * @see FoldLeft */ -public final class ScanLeft implements Fn3, B, Iterable, Iterable> { +public final class ScanLeft implements Fn3, B, Iterable, Iterable> { - private static final ScanLeft INSTANCE = new ScanLeft(); + private static final ScanLeft INSTANCE = new ScanLeft<>(); private ScanLeft() { } @Override - public Iterable apply(BiFunction fn, B b, Iterable as) { + public Iterable checkedApply(Fn2 fn, B b, Iterable as) { return () -> new ScanningIterator<>(fn, b, as.iterator()); } @SuppressWarnings("unchecked") public static ScanLeft scanLeft() { - return INSTANCE; + return (ScanLeft) INSTANCE; } - public static Fn2, Iterable> scanLeft(BiFunction fn) { + public static Fn2, Iterable> scanLeft(Fn2 fn) { return ScanLeft.scanLeft().apply(fn); } - public static Fn1, Iterable> scanLeft(BiFunction fn, B b) { + public static Fn1, Iterable> scanLeft(Fn2 fn, B b) { return ScanLeft.scanLeft(fn).apply(b); } - public static Iterable scanLeft(BiFunction fn, B b, Iterable as) { + public static Iterable scanLeft(Fn2 fn, B b, Iterable as) { return ScanLeft.scanLeft(fn, b).apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Times.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Times.java index cdf33a8d7..c23277e63 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Times.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Times.java @@ -4,8 +4,6 @@ import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.Fn3; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn2.Replicate.replicate; import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft; @@ -20,15 +18,15 @@ * * @param the input and output type */ -public final class Times implements Fn3, A, A> { +public final class Times implements Fn3, A, A> { - private static final Times INSTANCE = new Times(); + private static final Times INSTANCE = new Times<>(); private Times() { } @Override - public A apply(Integer n, Function fn, A a) { + public A checkedApply(Integer n, Fn1 fn, A a) { if (n < 0) throw new IllegalStateException("n must not be less than 0"); @@ -37,18 +35,18 @@ public A apply(Integer n, Function fn, A a) { @SuppressWarnings("unchecked") public static Times times() { - return INSTANCE; + return (Times) INSTANCE; } - public static Fn2, A, A> times(Integer n) { + public static Fn2, A, A> times(Integer n) { return Times.times().apply(n); } - public static Fn1 times(Integer n, Function fn) { + public static Fn1 times(Integer n, Fn1 fn) { return Times.times(n).apply(fn); } - public static A times(Integer n, Function fn, A a) { + public static A times(Integer n, Fn1 fn, A a) { return Times.times(n, fn).apply(a); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ZipWith.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ZipWith.java index 75266b884..f9af0c1f2 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ZipWith.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ZipWith.java @@ -3,9 +3,7 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.Fn3; -import com.jnape.palatable.lambda.iteration.ZippingIterator; - -import java.util.function.BiFunction; +import com.jnape.palatable.lambda.internal.iteration.ZippingIterator; /** * Zip together two Iterables by applying a zipping function to the successive elements of each @@ -17,34 +15,35 @@ * @param The output Iterable element type * @see com.jnape.palatable.lambda.functions.builtin.fn2.Zip */ -public final class ZipWith implements Fn3, Iterable, Iterable, Iterable> { +public final class ZipWith implements Fn3, Iterable, Iterable, Iterable> { - private static final ZipWith INSTANCE = new ZipWith(); + private static final ZipWith INSTANCE = new ZipWith<>(); private ZipWith() { } @Override - public Iterable apply(BiFunction zipper, Iterable as, Iterable bs) { + public Iterable checkedApply(Fn2 zipper, Iterable as, + Iterable bs) { return () -> new ZippingIterator<>(zipper, as.iterator(), bs.iterator()); } @SuppressWarnings("unchecked") public static ZipWith zipWith() { - return INSTANCE; + return (ZipWith) INSTANCE; } public static Fn2, Iterable, Iterable> zipWith( - BiFunction zipper) { + Fn2 zipper) { return ZipWith.zipWith().apply(zipper); } - public static Fn1, Iterable> zipWith(BiFunction zipper, + public static Fn1, Iterable> zipWith(Fn2 zipper, Iterable as) { return ZipWith.zipWith(zipper).apply(as); } - public static Iterable zipWith(BiFunction zipper, Iterable as, + public static Iterable zipWith(Fn2 zipper, Iterable as, Iterable bs) { return ZipWith.zipWith(zipper, as).apply(bs); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/IfThenElse.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/IfThenElse.java index d67440595..70336b79a 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/IfThenElse.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/IfThenElse.java @@ -5,46 +5,43 @@ import com.jnape.palatable.lambda.functions.Fn3; import com.jnape.palatable.lambda.functions.Fn4; -import java.util.function.Function; +public final class IfThenElse implements + Fn4, Fn1, Fn1, A, B> { -public final class IfThenElse implements Fn4, Function, Function, A, B> { - - private static final IfThenElse INSTANCE = new IfThenElse(); + private static final IfThenElse INSTANCE = new IfThenElse<>(); private IfThenElse() { } @Override - public B apply(Function predicate, Function thenCase, - Function elseCase, A a) { + public B checkedApply(Fn1 predicate, Fn1 thenCase, + Fn1 elseCase, A a) { return predicate.apply(a) ? thenCase.apply(a) : elseCase.apply(a); } @SuppressWarnings("unchecked") public static IfThenElse ifThenElse() { - return INSTANCE; + return (IfThenElse) INSTANCE; } - public static Fn3, Function, A, B> ifThenElse( - Function predicate) { + public static Fn3, Fn1, A, B> ifThenElse( + Fn1 predicate) { return IfThenElse.ifThenElse().apply(predicate); } - public static Fn2, A, B> ifThenElse( - Function predicate, Function thenCase) { + public static Fn2, A, B> ifThenElse(Fn1 predicate, + Fn1 thenCase) { return IfThenElse.ifThenElse(predicate).apply(thenCase); } - public static Fn1 ifThenElse( - Function predicate, Function thenCase, - Function elseCase) { + public static Fn1 ifThenElse(Fn1 predicate, + Fn1 thenCase, + Fn1 elseCase) { return IfThenElse.ifThenElse(predicate, thenCase).apply(elseCase); } - public static B ifThenElse( - Function predicate, Function thenCase, - Function elseCase, - A a) { + public static B ifThenElse(Fn1 predicate, Fn1 thenCase, + Fn1 elseCase, A a) { return ifThenElse(predicate, thenCase, elseCase).apply(a); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/LiftA3.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/LiftA3.java index a34a1aaae..b8ccd2527 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/LiftA3.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/LiftA3.java @@ -22,34 +22,34 @@ * @see Applicative#zip(Applicative) */ public final class LiftA3, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, AppD extends Applicative> implements Fn4, AppA, AppB, AppC, AppD> { - private static final LiftA3 INSTANCE = new LiftA3(); + private static final LiftA3 INSTANCE = new LiftA3<>(); private LiftA3() { } @Override - public AppD apply(Fn3 fn, AppA appA, AppB appB, AppC appC) { + public AppD checkedApply(Fn3 fn, AppA appA, AppB appB, AppC appC) { return appC.zip(appB.zip(appA.fmap(fn))).coerce(); } @SuppressWarnings("unchecked") public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, AppD extends Applicative> LiftA3 liftA3() { - return INSTANCE; + return (LiftA3) INSTANCE; } public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -58,7 +58,7 @@ AppD extends Applicative> Fn3 liftA3(Fn3, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -67,7 +67,7 @@ AppD extends Applicative> Fn2 liftA3(Fn3 f } public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -76,7 +76,7 @@ AppD extends Applicative> Fn1 liftA3(Fn3 fn, App } public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimit.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimit.java index 4c7ad843e..53d9b7189 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimit.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimit.java @@ -1,35 +1,38 @@ package com.jnape.palatable.lambda.functions.builtin.fn4; +import com.jnape.palatable.lambda.functions.Fn0; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.Fn3; import com.jnape.palatable.lambda.functions.Fn4; -import com.jnape.palatable.lambda.iteration.IterationInterruptedException; -import com.jnape.palatable.lambda.iteration.RateLimitingIterable; +import com.jnape.palatable.lambda.internal.iteration.IterationInterruptedException; +import com.jnape.palatable.lambda.internal.iteration.RateLimitingIterable; import java.time.Duration; import java.time.Instant; -import java.util.function.Supplier; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static java.util.Collections.singleton; /** - * Given a {@link Supplier} of {@link Instant Instants} (presumably backed by a clock), a limit, a {@link - * Duration}, and an {@link Iterable} as, return an {@link Iterable} that iterates as - * according to the threshold specified by the limit per duration, using the {@link Supplier} to advance time. + * Given an {@link Fn0} of {@link Instant Instants} (presumably backed by a clock), a limit, a + * {@link Duration}, and an {@link Iterable} as, return an {@link Iterable} that iterates as + * according to the threshold specified by the limit per duration, using the {@link Fn0} to advance time. *

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


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

  * Iterable<Integer> elements = iterate(x -> x + 1, 1);
  *
- * Supplier<Instant> instantSupplier = Clock.systemUTC()::instant;
- * Fn1<Iterable<Integer>, Iterable<Integer>> tenPerSecond = rateLimit(instantSupplier, 10L, Duration.ofSeconds(1));
- * Fn1<Iterable<Integer>, Iterable<Integer>> oneHundredEveryTwoMinutes = rateLimit(instantSupplier, 100L, Duration.ofMinutes(2));
+ * Supplier<Instant> instantFn0 = Clock.systemUTC()::instant;
+ * Fn1<Iterable<Integer>, Iterable<Integer>> tenPerSecond =
+ *     rateLimit(instantFn0, 10L, Duration.ofSeconds(1));
+ * Fn1<Iterable<Integer>, Iterable<Integer>> oneHundredEveryTwoMinutes =
+ *     rateLimit(instantFn0, 100L, Duration.ofMinutes(2));
  *
  * tenPerSecond.fmap(oneHundredEveryTwoMinutes).apply(elements).forEach(System.out::println);
  * 
@@ -45,41 +48,39 @@ * * @param
the {@link Iterable} element type */ -public final class RateLimit implements Fn4, Long, Duration, Iterable, Iterable> { +public final class RateLimit implements Fn4, Long, Duration, Iterable, Iterable> { - private static final RateLimit INSTANCE = new RateLimit(); + private static final RateLimit INSTANCE = new RateLimit<>(); private RateLimit() { } @Override - public Iterable apply(Supplier instantSupplier, Long limit, Duration duration, Iterable as) { + public Iterable checkedApply(Fn0 instantFn0, Long limit, Duration duration, Iterable as) { if (limit < 1) throw new IllegalArgumentException("Limit must be greater than 0: " + limit); - return new RateLimitingIterable<>(as, singleton(tuple(limit, duration, instantSupplier))); + return new RateLimitingIterable<>(as, singleton(tuple(limit, duration, instantFn0))); } @SuppressWarnings("unchecked") public static RateLimit rateLimit() { - return INSTANCE; + return (RateLimit) INSTANCE; } - public static Fn3, Iterable> rateLimit(Supplier instantSupplier) { - return RateLimit.rateLimit().apply(instantSupplier); + public static Fn3, Iterable> rateLimit(Fn0 instantFn0) { + return RateLimit.rateLimit().apply(instantFn0); } - public static Fn2, Iterable> rateLimit(Supplier instantSupplier, Long limit) { - return RateLimit.rateLimit(instantSupplier).apply(limit); + public static Fn2, Iterable> rateLimit(Fn0 instantFn0, Long limit) { + return RateLimit.rateLimit(instantFn0).apply(limit); } - public static Fn1, Iterable> rateLimit(Supplier instantSupplier, Long limit, - Duration duration) { - return RateLimit.rateLimit(instantSupplier, limit).apply(duration); + public static Fn1, Iterable> rateLimit(Fn0 instantFn0, Long limit, Duration duration) { + return RateLimit.rateLimit(instantFn0, limit).apply(duration); } - public static Iterable rateLimit(Supplier instantSupplier, Long limit, Duration duration, - Iterable as) { - return RateLimit.rateLimit(instantSupplier, limit, duration).apply(as); + public static Iterable rateLimit(Fn0 instantFn0, Long limit, Duration duration, Iterable as) { + return RateLimit.rateLimit(instantFn0, limit, duration).apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn5/LiftA4.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn5/LiftA4.java index 099d519ca..408f94652 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn5/LiftA4.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn5/LiftA4.java @@ -25,36 +25,36 @@ * @see Applicative#zip(Applicative) */ public final class LiftA4, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, AppD extends Applicative, AppE extends Applicative> implements Fn5, AppA, AppB, AppC, AppD, AppE> { - private static final LiftA4 INSTANCE = new LiftA4(); + private static final LiftA4 INSTANCE = new LiftA4<>(); private LiftA4() { } @Override - public AppE apply(Fn4 fn, AppA appA, AppB appB, AppC appC, AppD appD) { + public AppE checkedApply(Fn4 fn, AppA appA, AppB appB, AppC appC, AppD appD) { return appD.zip(appC.zip(appB.zip(appA.fmap(fn)))).coerce(); } @SuppressWarnings("unchecked") public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, AppD extends Applicative, AppE extends Applicative> LiftA4 liftA4() { - return INSTANCE; + return (LiftA4) INSTANCE; } public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -64,7 +64,7 @@ AppE extends Applicative> Fn4 liftA4(Fn4, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -74,7 +74,7 @@ AppE extends Applicative> Fn3 liftA4(Fn4, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -85,7 +85,7 @@ AppE extends Applicative> Fn2 liftA4(Fn4, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -96,7 +96,7 @@ AppE extends Applicative> Fn1 liftA4(Fn4 fn, } public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn6/LiftA5.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn6/LiftA5.java index f32d44569..4711de30a 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn6/LiftA5.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn6/LiftA5.java @@ -28,7 +28,7 @@ * @see Applicative#zip(Applicative) */ public final class LiftA5, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -36,30 +36,30 @@ public final class LiftA5, AppF extends Applicative> implements Fn6, AppA, AppB, AppC, AppD, AppE, AppF> { - private static final LiftA5 INSTANCE = new LiftA5(); + private static final LiftA5 INSTANCE = new LiftA5<>(); private LiftA5() { } @Override - public AppF apply(Fn5 fn, AppA appA, AppB appB, AppC appC, AppD appD, AppE appE) { + public AppF checkedApply(Fn5 fn, AppA appA, AppB appB, AppC appC, AppD appD, AppE appE) { return appE.zip(appD.zip(appC.zip(appB.zip(appA.fmap(fn))))).coerce(); } @SuppressWarnings("unchecked") public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, AppD extends Applicative, AppE extends Applicative, AppF extends Applicative> LiftA5 liftA5() { - return INSTANCE; + return (LiftA5) INSTANCE; } public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -70,7 +70,7 @@ AppF extends Applicative> Fn5 liftA5 } public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -82,7 +82,7 @@ AppF extends Applicative> Fn4 liftA5(Fn5, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -94,7 +94,7 @@ AppF extends Applicative> Fn3 liftA5(Fn5, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -107,7 +107,7 @@ AppF extends Applicative> Fn2 liftA5(Fn5, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -119,7 +119,7 @@ AppF extends Applicative> Fn1 liftA5(Fn5 f } public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn7/LiftA6.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn7/LiftA6.java index 72da45314..90234684d 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn7/LiftA6.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn7/LiftA6.java @@ -31,42 +31,44 @@ * @see Applicative#zip(Applicative) */ public final class LiftA6, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, AppD extends Applicative, AppE extends Applicative, AppF extends Applicative, - AppG extends Applicative> implements Fn7, AppA, AppB, AppC, AppD, AppE, AppF, AppG> { + AppG extends Applicative> implements + Fn7, AppA, AppB, AppC, AppD, AppE, AppF, AppG> { - private static final LiftA6 INSTANCE = new LiftA6(); + private static final LiftA6 INSTANCE = new LiftA6<>(); private LiftA6() { } @Override - public AppG apply(Fn6 fn, AppA appA, AppB appB, AppC appC, AppD appD, AppE appE, - AppF appF) { + public AppG checkedApply(Fn6 fn, AppA appA, AppB appB, AppC appC, AppD appD, AppE appE, + AppF appF) { return appF.zip(appE.zip(appD.zip(appC.zip(appB.zip(appA.fmap(fn)))))).coerce(); } @SuppressWarnings("unchecked") public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, AppD extends Applicative, AppE extends Applicative, AppF extends Applicative, - AppG extends Applicative> LiftA6 liftA6() { - return INSTANCE; + AppG extends Applicative> + LiftA6 liftA6() { + return (LiftA6) INSTANCE; } public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -79,7 +81,7 @@ AppG extends Applicative> Fn6 } public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -93,7 +95,7 @@ AppG extends Applicative> Fn5 liftA6 } public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -107,7 +109,7 @@ AppG extends Applicative> Fn4 liftA6(Fn6, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -121,7 +123,7 @@ AppG extends Applicative> Fn3 liftA6(Fn6, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -135,7 +137,7 @@ AppG extends Applicative> Fn2 liftA6(Fn6, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -148,7 +150,7 @@ AppG extends Applicative> Fn1 liftA6(Fn6, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn8/LiftA7.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn8/LiftA7.java index 6d508f06d..90eab07a5 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn8/LiftA7.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn8/LiftA7.java @@ -34,7 +34,7 @@ * @see Applicative#zip(Applicative) */ public final class LiftA7, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -44,20 +44,20 @@ public final class LiftA7, AppH extends Applicative> implements Fn8, AppA, AppB, AppC, AppD, AppE, AppF, AppG, AppH> { - private static final LiftA7 INSTANCE = new LiftA7(); + private static final LiftA7 INSTANCE = new LiftA7<>(); private LiftA7() { } @Override - public AppH apply(Fn7 fn, AppA appA, AppB appB, AppC appC, AppD appD, AppE appE, - AppF appF, AppG appG) { + public AppH checkedApply(Fn7 fn, AppA appA, AppB appB, AppC appC, AppD appD, AppE appE, + AppF appF, AppG appG) { return appG.zip(appF.zip(appE.zip(appD.zip(appC.zip(appB.zip(appA.fmap(fn))))))).coerce(); } @SuppressWarnings("unchecked") public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -66,11 +66,11 @@ public AppH apply(Fn7 fn, AppA appA, AppB appB, AppC app AppF extends Applicative, AppG extends Applicative, AppH extends Applicative> LiftA7 liftA7() { - return INSTANCE; + return (LiftA7) INSTANCE; } public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -84,7 +84,7 @@ AppH extends Applicative> Fn7, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -98,7 +98,7 @@ AppH extends Applicative> Fn6 } public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -112,7 +112,7 @@ AppH extends Applicative> Fn5 liftA7 } public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -127,7 +127,7 @@ AppH extends Applicative> Fn4 liftA7(Fn7, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -142,7 +142,7 @@ AppH extends Applicative> Fn3 liftA7(Fn7, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -156,7 +156,7 @@ AppH extends Applicative> Fn2 liftA7(Fn7, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -171,7 +171,7 @@ AppH extends Applicative> Fn1 liftA7(Fn7, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, diff --git a/src/main/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResult.java b/src/main/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResult.java index 7da780a1e..c21c62908 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResult.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResult.java @@ -1,13 +1,13 @@ package com.jnape.palatable.lambda.functions.recursion; import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; -import java.util.function.Function; /** * Specialized {@link CoProduct2} representing the possible results of a primitive recursive function. @@ -30,25 +30,24 @@ public RecursiveResult invert() { @Override @SuppressWarnings("unchecked") - public RecursiveResult biMapL(Function fn) { + public RecursiveResult biMapL(Fn1 fn) { return (RecursiveResult) Bifunctor.super.biMapL(fn); } @Override @SuppressWarnings("unchecked") - public RecursiveResult biMapR(Function fn) { + public RecursiveResult biMapR(Fn1 fn) { return (RecursiveResult) Bifunctor.super.biMapR(fn); } @Override - public RecursiveResult biMap(Function lFn, - Function rFn) { + public RecursiveResult biMap(Fn1 lFn, + Fn1 rFn) { return match(a -> recurse(lFn.apply(a)), b -> terminate(rFn.apply(b))); } @Override - public RecursiveResult flatMap( - Function>> f) { + public RecursiveResult flatMap(Fn1>> f) { return match(RecursiveResult::recurse, b -> f.apply(b).coerce()); } @@ -58,13 +57,12 @@ public RecursiveResult pure(C c) { } @Override - public RecursiveResult fmap(Function fn) { + public RecursiveResult fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } @Override - public RecursiveResult zip( - Applicative, RecursiveResult> appFn) { + public RecursiveResult zip(Applicative, RecursiveResult> appFn) { return Monad.super.zip(appFn).coerce(); } @@ -79,10 +77,11 @@ public RecursiveResult discardR(Applicative> } @Override - @SuppressWarnings("unchecked") - public >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { - return match(__ -> pure.apply(coerce()), b -> fn.apply(b).fmap(this::pure).fmap(Applicative::coerce).coerce()); + public , TravB extends Traversable>, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, + Fn1 pure) { + return match(__ -> pure.apply(coerce()), + b -> fn.apply(b).fmap(this::pure).fmap(RecursiveResult::coerce).coerce()); } public static RecursiveResult recurse(A a) { @@ -101,7 +100,7 @@ private Recurse(A a) { } @Override - public R match(Function aFn, Function bFn) { + public R match(Fn1 aFn, Fn1 bFn) { return aFn.apply(a); } @@ -131,7 +130,7 @@ private Terminate(B b) { } @Override - public R match(Function aFn, Function bFn) { + public R match(Fn1 aFn, Fn1 bFn) { return bFn.apply(b); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/recursion/Trampoline.java b/src/main/java/com/jnape/palatable/lambda/functions/recursion/Trampoline.java index a4efb94cc..6637219ec 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/recursion/Trampoline.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/recursion/Trampoline.java @@ -7,25 +7,23 @@ import com.jnape.palatable.lambda.functions.recursion.RecursiveResult.Recurse; import com.jnape.palatable.lambda.functions.recursion.RecursiveResult.Terminate; -import java.util.function.Function; - /** - * Given a {@link Function}<A, {@link CoProduct2}<A, B, ?>> (analogous to "recurse" and - * "return" tail position instructions, respectively), produce a {@link Function}<A, B> that - * unrolls the original function by iteratively passing each result that matches the input (A) back - * to the original function, and then terminating on and returning the first output (B). + * Given an {@link Fn1}<A, {@link CoProduct2}<A, B, ?>> (analogous to "recurse" and "return" + * tail position instructions, respectively), produce a {@link Fn1}<A, B> that unrolls the original + * function by iteratively passing each result that matches the input (A) back to the original function, + * and then terminating on and returning the first output (B). *

* This is isomorphic to - though presumably faster than - taking the last element of an {@link Unfoldr} call. * * @param the trampolined function's input type * @param the trampolined function's output type */ -public final class Trampoline implements Fn2>, A, B> { +public final class Trampoline implements Fn2>, A, B> { - private static final Trampoline INSTANCE = new Trampoline<>(); + private static final Trampoline INSTANCE = new Trampoline<>(); @Override - public B apply(Function> fn, A a) { + public B checkedApply(Fn1> fn, A a) { RecursiveResult next = fn.apply(a); while (next instanceof Recurse) next = fn.apply(((Recurse) next).a); @@ -34,14 +32,14 @@ public B apply(Function> fn, A a) { @SuppressWarnings("unchecked") public static Trampoline trampoline() { - return INSTANCE; + return (Trampoline) INSTANCE; } - public static Fn1 trampoline(Function> fn) { + public static Fn1 trampoline(Fn1> fn) { return Trampoline.trampoline().apply(fn); } - public static B trampoline(Function> fn, A a) { + public static B trampoline(Fn1> fn, A a) { return trampoline(fn).apply(a); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiMonoidFactory.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiMonoidFactory.java index 352de9585..198316f00 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiMonoidFactory.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiMonoidFactory.java @@ -1,22 +1,37 @@ package com.jnape.palatable.lambda.functions.specialized; import com.jnape.palatable.lambda.adt.product.Product2; +import com.jnape.palatable.lambda.internal.Runtime; import com.jnape.palatable.lambda.monoid.Monoid; @FunctionalInterface public interface BiMonoidFactory extends BiSemigroupFactory { @Override - default MonoidFactory apply(A a) { - return b -> apply(a, b); + Monoid checkedApply(A a, B b) throws Throwable; + + @Override + default MonoidFactory checkedApply(A a) throws Throwable { + return b -> checkedApply(a, b); + } + + @Override + default Monoid apply(A a, B b) { + try { + return checkedApply(a, b); + } catch (Throwable t) { + throw Runtime.throwChecked(t); + } } @Override - Monoid apply(A a, B b); + default MonoidFactory apply(A a) { + return b -> apply(a, b); + } @Override default BiMonoidFactory flip() { - return (b, a) -> apply(a, b); + return (b, a) -> checkedApply(a, b); } @Override diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiPredicate.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiPredicate.java index 8d28fb290..54d11cd92 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiPredicate.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiPredicate.java @@ -1,42 +1,41 @@ package com.jnape.palatable.lambda.functions.specialized; import com.jnape.palatable.lambda.adt.product.Product2; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; - -import java.util.function.Function; +import com.jnape.palatable.lambda.functor.Applicative; /** - * A specialized {@link Fn2} that returns a Boolean when fully applied, - * or a {@link Predicate} when partially applied. + * A specialized {@link Fn2} that returns a Boolean when fully applied, or a {@link Predicate} when partially applied. * * @param the first argument type * @param the second argument type */ @FunctionalInterface -public interface BiPredicate extends Fn2, java.util.function.BiPredicate { +public interface BiPredicate extends Fn2 { /** * {@inheritDoc} */ @Override - default boolean test(A a, B b) { - return apply(a, b); + default Predicate apply(A a) { + return Fn2.super.apply(a)::apply; } /** * {@inheritDoc} */ @Override - default Predicate apply(A a) { - return Fn2.super.apply(a)::apply; + default BiPredicate flip() { + return Fn2.super.flip()::apply; } /** * {@inheritDoc} */ @Override - default BiPredicate flip() { - return Fn2.super.flip()::apply; + default BiPredicate discardR(Applicative> appB) { + return Fn2.super.discardR(appB)::apply; } /** @@ -51,7 +50,7 @@ default BiPredicate flip() { * {@inheritDoc} */ @Override - default BiPredicate diMapL(Function fn) { + default BiPredicate diMapL(Fn1 fn) { return Fn2.super.diMapL(fn)::apply; } @@ -59,42 +58,57 @@ default BiPredicate diMapL(Function fn) { * {@inheritDoc} */ @Override - default Fn2 contraMap(Function fn) { + default Fn2 contraMap(Fn1 fn) { return Fn2.super.contraMap(fn)::apply; } /** - * Override of {@link java.util.function.BiPredicate#and(java.util.function.BiPredicate)}, returning an instance of - * BiPredicate for compatibility. Left-to-right composition. + * Left-to-right short-circuiting logical conjunction. * * @param other the biPredicate to test if this one succeeds * @return a biPredicate representing the conjunction of this biPredicate and other */ - @Override - default BiPredicate and(java.util.function.BiPredicate other) { - return (a, b) -> apply(a, b) && other.test(a, b); + default BiPredicate and(BiPredicate other) { + return (a, b) -> apply(a, b) && other.apply(a, b); } /** - * Override of {@link java.util.function.BiPredicate#or(java.util.function.BiPredicate)}, returning an instance of - * BiPredicate for compatibility. Left-to-right composition. + * Left-to-right short-circuiting logical disjunction. * * @param other the biPredicate to test if this one fails * @return a biPredicate representing the disjunction of this biPredicate and other */ - @Override - default BiPredicate or(java.util.function.BiPredicate other) { - return (a, b) -> apply(a, b) || other.test(a, b); + default BiPredicate or(BiPredicate other) { + return (a, b) -> apply(a, b) || other.apply(a, b); } /** - * Override of {@link java.util.function.BiPredicate#negate()}, returning an instance of BiPredicate - * for compatibility. + * Logical negation. * * @return the negation of this biPredicate */ - @Override default BiPredicate negate() { return (a, b) -> !apply(a, b); } + + /** + * Convert this {@link BiPredicate} to a java {@link java.util.function.BiPredicate}. + * + * @return {@link java.util.function.BiPredicate} + */ + default java.util.function.BiPredicate toBiPredicate() { + return this::apply; + } + + /** + * Create a {@link BiPredicate} from a java {@link java.util.function.BiPredicate}. + * + * @param biPredicate the {@link java.util.function.BiPredicate} + * @param the first input type + * @param the second input type + * @return the {@link BiPredicate} + */ + static BiPredicate fromBiPredicate(java.util.function.BiPredicate biPredicate) { + return biPredicate::test; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiSemigroupFactory.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiSemigroupFactory.java index a2a16d899..5cf0a4a17 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiSemigroupFactory.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiSemigroupFactory.java @@ -8,7 +8,17 @@ public interface BiSemigroupFactory extends Fn4 { @Override - Semigroup apply(A a, B b); + Semigroup checkedApply(A a, B b) throws Throwable; + + @Override + default C checkedApply(A a, B b, C c, C d) throws Throwable { + return checkedApply(a, b).checkedApply(c, d); + } + + @Override + default Semigroup apply(A a, B b) { + return Fn4.super.apply(a, b)::apply; + } @Override default SemigroupFactory apply(A a) { @@ -24,9 +34,4 @@ default BiSemigroupFactory flip() { default SemigroupFactory, C> uncurry() { return ab -> apply(ab._1(), ab._2()); } - - @Override - default C apply(A a, B b, C c, C d) { - return apply(a).apply(b).apply(c, d); - } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Kleisli.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Kleisli.java index 433ef410f..ad66e4036 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Kleisli.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Kleisli.java @@ -4,18 +4,16 @@ import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.monad.Monad; -import java.util.function.Function; - /** * The Kleisli arrow of a {@link Monad}, manifest as simply an {@link Fn1}<A, MB>. This can be - * thought of as a fixed, portable {@link Monad#flatMap(Function)}. + * thought of as a fixed, portable {@link Monad#flatMap(Fn1)}. * * @param the input argument type * @param the {@link Monad} unification parameter * @param the output {@link Monad} type */ @FunctionalInterface -public interface Kleisli> extends Fn1 { +public interface Kleisli, MB extends Monad> extends Fn1 { /** * Left-to-right composition of two compatible {@link Kleisli} arrows, yielding a new {@link Kleisli} arrow. @@ -25,6 +23,7 @@ public interface Kleisli> extends * @param the {@link Monad} instance to return * @return the composition of the two arrows as a new {@link Kleisli} arrow */ + @SuppressWarnings("overloads") default > Kleisli andThen(Kleisli after) { return a -> apply(a).flatMap(after).coerce(); } @@ -37,18 +36,11 @@ default > Kleisli andThen(Kleisli the {@link Monad} instance to flatMap with this arrow * @return the composition of the two arrows as a new {@link Kleisli} arrow */ + @SuppressWarnings("overloads") default > Kleisli compose(Kleisli before) { return z -> before.apply(z).flatMap(this).coerce(); } - /** - * {@inheritDoc} - */ - @Override - default Kleisli compose(Function before) { - return Fn1.super.compose(before)::apply; - } - /** * {@inheritDoc} */ @@ -61,7 +53,7 @@ default Kleisli discardR(Applicative> appB) { * {@inheritDoc} */ @Override - default Kleisli contraMap(Function fn) { + default Kleisli contraMap(Fn1 fn) { return Fn1.super.contraMap(fn)::apply; } @@ -69,7 +61,7 @@ default Kleisli contraMap(Function fn) * {@inheritDoc} */ @Override - default Kleisli diMapL(Function fn) { + default Kleisli diMapL(Fn1 fn) { return Fn1.super.diMapL(fn)::apply; } @@ -83,8 +75,8 @@ default Kleisli diMapL(Function fn) { * @param the returned {@link Monad} instance * @return the function adapted as a {@link Kleisli} arrow */ - static > Kleisli kleisli( - Function fn) { + static , MB extends Monad> Kleisli kleisli( + Fn1 fn) { return fn::apply; } } \ No newline at end of file diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/MonoidFactory.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/MonoidFactory.java index 68657a104..1bcbb4314 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/MonoidFactory.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/MonoidFactory.java @@ -1,14 +1,24 @@ package com.jnape.palatable.lambda.functions.specialized; +import com.jnape.palatable.lambda.internal.Runtime; import com.jnape.palatable.lambda.monoid.Monoid; public interface MonoidFactory extends SemigroupFactory { + @Override + Monoid checkedApply(A a) throws Throwable; + @Override default B apply(A a, B b, B c) { return apply(a).apply(b, c); } @Override - Monoid apply(A a); + default Monoid apply(A a) { + try { + return checkedApply(a); + } catch (Throwable t) { + throw Runtime.throwChecked(t); + } + } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Noop.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Noop.java deleted file mode 100644 index 62c5192f4..000000000 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Noop.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.jnape.palatable.lambda.functions.specialized; - -import com.jnape.palatable.lambda.functions.Effect; - -/** - * As the name might suggest, this is an {@link Effect} that, *ahem*, has no effect. - * - * @param the argument type - */ -public final class Noop implements Effect { - private static final Noop INSTANCE = new Noop(); - - private Noop() { - } - - @Override - public void accept(A a) { - } - - /** - * Static factory method that returns the singleton {@link Noop} instance. - * - * @param the argument type - * @return the singleton {@link Noop} instance - */ - @SuppressWarnings("unchecked") - public static Noop noop() { - return INSTANCE; - } -} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Predicate.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Predicate.java index 2138db821..f5e849bb4 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Predicate.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Predicate.java @@ -1,96 +1,114 @@ package com.jnape.palatable.lambda.functions.specialized; import com.jnape.palatable.lambda.functions.Fn1; - -import java.util.function.Function; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functor.Applicative; /** * A specialized {@link Fn1} that returns a Boolean. * * @param The argument type */ -public interface Predicate extends Fn1, java.util.function.Predicate { +@FunctionalInterface +public interface Predicate extends Fn1 { /** * {@inheritDoc} */ @Override - default boolean test(A a) { - return apply(a); + default Predicate diMapL(Fn1 fn) { + return Fn1.super.diMapL(fn)::apply; } /** - * Override of {@link Function#compose(Function)}, returning an instance of Predicate for - * compatibility. Right-to-left composition. - * - * @param before the function who's return value is this predicate's argument - * @param the new argument type - * @return a new predicate of Z (the new argument type) + * {@inheritDoc} */ @Override - default Predicate compose(Function before) { - return Fn1.super.compose(before)::apply; + default Predicate contraMap(Fn1 fn) { + return Fn1.super.contraMap(fn)::apply; } /** * {@inheritDoc} */ @Override - default Predicate diMapL(Function fn) { - return Fn1.super.diMapL(fn)::apply; + default BiPredicate widen() { + return Fn1.super.widen()::checkedApply; } /** * {@inheritDoc} */ @Override - default Predicate contraMap(Function fn) { - return Fn1.super.contraMap(fn)::apply; + default Predicate discardR(Applicative> appB) { + return Fn1.super.discardR(appB)::checkedApply; + } + + /** + * {@inheritDoc} + */ + @Override + default BiPredicate compose(Fn2 before) { + return Fn1.super.compose(before)::apply; } /** - * Override of {@link java.util.function.Predicate#and(java.util.function.Predicate)}, returning an instance of - * Predicate for compatibility. Left-to-right composition. + * Left-to-right short-circuiting logical conjunction. * * @param other the predicate to test if this one succeeds * @return a predicate representing the conjunction of this predicate and other */ - @Override - default Predicate and(java.util.function.Predicate other) { - return a -> apply(a) && other.test(a); + default Predicate and(Predicate other) { + return a -> apply(a) && other.apply(a); } /** - * Override of {@link java.util.function.Predicate#or(java.util.function.Predicate)}, returning an instance of - * Predicate for compatibility. Left-to-right composition. + * Left-to-right short-circuiting logical disjunction. * * @param other the predicate to test if this one fails * @return a predicate representing the disjunction of this predicate and other */ - @Override - default Predicate or(java.util.function.Predicate other) { - return a -> apply(a) || other.test(a); + default Predicate or(Predicate other) { + return a -> apply(a) || other.apply(a); } /** - * Override of {@link java.util.function.Predicate#negate()}, returning an instance of Predicate for - * compatibility. + * Logical negation. * * @return the negation of this predicate */ - @Override default Predicate negate() { return a -> !apply(a); } /** - * Static factory method to create a predicate from a function. + * Convert this {@link Predicate} to a java {@link java.util.function.Predicate}. + * + * @return the {@link java.util.function.Predicate} + */ + default java.util.function.Predicate toPredicate() { + return this::apply; + } + + /** + * Static factory method to create a predicate from an {@link Fn1}. * - * @param predicate the function + * @param predicate the {@link Fn1} * @param the input type * @return the predicate */ - static Predicate predicate(Function predicate) { + static Predicate predicate(Fn1 predicate) { return predicate::apply; } + + /** + * Create a {@link Predicate} from a java {@link java.util.function.Predicate}. + * + * @param predicate the java {@link java.util.function.Predicate} + * @param the input type + * @return the {@link Predicate} + */ + static Predicate fromPredicate(java.util.function.Predicate predicate) { + return predicate::test; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Pure.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Pure.java new file mode 100644 index 000000000..77d3bd91a --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Pure.java @@ -0,0 +1,36 @@ +package com.jnape.palatable.lambda.functions.specialized; + +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.Functor; +import com.jnape.palatable.lambda.internal.Runtime; + +/** + * Generalized, portable {@link Applicative#pure(Object)}, with a loosened {@link Functor} constraint. + * + * @param the {@link Functor} to lift into + */ +@FunctionalInterface +public interface Pure> { + + Functor checkedApply(A a) throws Throwable; + + default > FA apply(A a) { + try { + @SuppressWarnings("unchecked") FA fa = (FA) checkedApply(a); + return fa; + } catch (Throwable t) { + throw Runtime.throwChecked(t); + } + } + + /** + * Static method to aid inference. + * + * @param pure the {@link Pure} + * @param the {@link Functor} witness + * @return the {@link Pure} + */ + static > Pure pure(Pure pure) { + return pure; + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/SemigroupFactory.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/SemigroupFactory.java index 4a47c277c..6d49d6a55 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/SemigroupFactory.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/SemigroupFactory.java @@ -7,10 +7,15 @@ public interface SemigroupFactory extends Fn3 { @Override - Semigroup apply(A a); + Semigroup checkedApply(A a) throws Throwable; @Override - default B apply(A a, B b, B c) { - return apply(a).apply(b, c); + default Semigroup apply(A a) { + return Fn3.super.apply(a)::apply; + } + + @Override + default B checkedApply(A a, B b, B c) throws Throwable { + return checkedApply(a).checkedApply(b, c); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/SideEffect.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/SideEffect.java new file mode 100644 index 000000000..6ef2092a1 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/SideEffect.java @@ -0,0 +1,59 @@ +package com.jnape.palatable.lambda.functions.specialized; + +import com.jnape.palatable.lambda.internal.Runtime; +import com.jnape.palatable.lambda.io.IO; + +/** + * An interface used to represent an effect that requires no input and produces no output, and therefore is only + * perceivable through inspection of some unreported state. Only exists because Java target-type inference requires an + * interface, or else this would all be internal, hence the inconveniently-named Ω. + *

+ * Ω should *never* be called directly. + * + * @see IO#io(SideEffect) + */ +public interface SideEffect { + + /** + * A no-op {@link SideEffect} + */ + SideEffect NOOP = () -> {}; + + @SuppressWarnings("NonAsciiCharacters") + void Ω() throws Throwable; + + /** + * Convert this {@link SideEffect} to a java {@link Runnable}. + * + * @return the {@link Runnable} + */ + default Runnable toRunnable() { + return () -> { + try { + Ω(); + } catch (Throwable t) { + throw Runtime.throwChecked(t); + } + }; + } + + /** + * Create a {@link SideEffect} from a java {@link Runnable}. + * + * @param runnable the {@link Runnable} + * @return the {@link SideEffect} + */ + static SideEffect fromRunnable(Runnable runnable) { + return runnable::run; + } + + /** + * Static factory method to aid in inference. + * + * @param sideEffect the {@link SideEffect} + * @return the {@link SideEffect} + */ + static SideEffect sideEffect(SideEffect sideEffect) { + return sideEffect; + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java deleted file mode 100644 index a4dc0c820..000000000 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java +++ /dev/null @@ -1,115 +0,0 @@ -package com.jnape.palatable.lambda.functions.specialized.checked; - -import com.jnape.palatable.lambda.adt.Unit; -import com.jnape.palatable.lambda.functions.Effect; -import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.functions.IO; - -import java.util.function.Consumer; -import java.util.function.Function; - -import static com.jnape.palatable.lambda.functions.specialized.checked.Runtime.throwChecked; -import static com.jnape.palatable.lambda.functions.IO.io; - -/** - * Specialized {@link Effect} that can throw any {@link Throwable}. - * - * @param The {@link Throwable} type - * @param The input type - * @see CheckedRunnable - * @see CheckedFn1 - * @see Effect - */ -@FunctionalInterface -public interface CheckedEffect extends Effect, CheckedFn1> { - - /** - * {@inheritDoc} - */ - @Override - default void accept(A a) { - try { - checkedAccept(a); - } catch (Throwable t) { - throw throwChecked(t); - } - } - - /** - * {@inheritDoc} - */ - @Override - default IO apply(A a) { - return io(() -> accept(a)); - } - - /** - * {@inheritDoc} - */ - @Override - default IO checkedApply(A a) throws T { - return apply(a); - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedEffect diMapL(Function fn) { - return Effect.super.diMapL(fn)::accept; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedEffect contraMap(Function fn) { - return Effect.super.contraMap(fn)::accept; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedEffect compose(Function before) { - return Effect.super.compose(before)::accept; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedEffect discardR(Applicative> appB) { - return Effect.super.discardR(appB)::accept; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedEffect andThen(Consumer after) { - return Effect.super.andThen(after)::accept; - } - - /** - * A version of {@link Effect#accept} that can throw checked exceptions. - * - * @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 deleted file mode 100644 index 4b5bd93a7..000000000 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1.java +++ /dev/null @@ -1,173 +0,0 @@ -package com.jnape.palatable.lambda.functions.specialized.checked; - -import com.jnape.palatable.lambda.adt.hlist.Tuple2; -import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.Fn2; -import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.monad.Monad; - -import java.util.function.Function; - -import static com.jnape.palatable.lambda.functions.specialized.checked.Runtime.throwChecked; - -/** - * Specialized {@link Fn1} that can throw any {@link Throwable}. - * - * @param The {@link Throwable} type - * @param The input type - * @param The output type - * @see CheckedSupplier - * @see CheckedRunnable - * @see Fn1 - */ -@FunctionalInterface -public interface CheckedFn1 extends Fn1 { - - /** - * {@inheritDoc} - */ - @Override - default B apply(A a) { - try { - return checkedApply(a); - } catch (Throwable t) { - throw throwChecked(t); - } - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedFn1 fmap(Function f) { - return Fn1.super.fmap(f)::apply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedFn1 flatMap(Function>> f) { - return Fn1.super.flatMap(f).>coerce()::apply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedFn1 discardL(Applicative> appB) { - return Fn1.super.discardL(appB)::apply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedFn1 discardR(Applicative> appB) { - return Fn1.super.discardR(appB)::apply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedFn1 zip(Applicative, Fn1> appFn) { - return Fn1.super.zip(appFn)::apply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedFn1 zip(Fn2 appFn) { - return Fn1.super.zip(appFn).coerce(); - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedFn1 diMapL(Function fn) { - return Fn1.super.diMapL(fn).coerce(); - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedFn1 diMapR(Function fn) { - return Fn1.super.diMapR(fn).coerce(); - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedFn1 diMap(Function lFn, - Function rFn) { - return Fn1.super.diMap(lFn, rFn)::apply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedFn1, Tuple2> strengthen() { - return Fn1.super.strengthen()::apply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedFn1> carry() { - return Fn1.super.carry()::apply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedFn1 contraMap(Function fn) { - return Fn1.super.contraMap(fn).coerce(); - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedFn1 compose(Function before) { - return Fn1.super.compose(before)::apply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedFn1 andThen(Function after) { - return Fn1.super.andThen(after)::apply; - } - - /** - * A version of {@link Fn1#apply} that can throw checked exceptions. - * - * @param a the function argument - * @return the application of the argument to the function - * @throws T any exception that can be thrown by this method - */ - B checkedApply(A a) throws T; - - /** - * Convenience static factory method for constructing a {@link CheckedFn1} without an explicit cast or type - * attribution at the call site. - * - * @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 deleted file mode 100644 index 7eb794917..000000000 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedRunnable.java +++ /dev/null @@ -1,65 +0,0 @@ -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; - -/** - * Specialized {@link Runnable} that can throw any {@link Throwable}. - * - * @param The {@link Throwable} type - * @see CheckedSupplier - * @see CheckedFn1 - */ -@FunctionalInterface -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() { - try { - checkedRun(); - } catch (Throwable t) { - throw throwChecked(t); - } - } - - @Override - default Unit unsafePerformIO() { - run(); - return UNIT; - } - - /** - * Convert this {@link CheckedRunnable} to a {@link CheckedSupplier} that returns {@link Unit}. - * - * @return the checked supplier - */ - default CheckedSupplier toSupplier() { - return () -> { - run(); - return UNIT; - }; - } - - /** - * Convenience static factory method for constructing a {@link CheckedRunnable} without an explicit cast or type - * attribution at the call site. - * - * @param runnable the checked runnable - * @param the inferred Throwable type - * @return the checked runnable - */ - static CheckedRunnable checked(CheckedRunnable runnable) { - return runnable::run; - } - -} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedSupplier.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedSupplier.java deleted file mode 100644 index 627da8c91..000000000 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedSupplier.java +++ /dev/null @@ -1,145 +0,0 @@ -package com.jnape.palatable.lambda.functions.specialized.checked; - -import com.jnape.palatable.lambda.adt.Unit; -import com.jnape.palatable.lambda.adt.hlist.Tuple2; -import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.Fn2; -import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.monad.Monad; - -import java.util.function.Function; -import java.util.function.Supplier; - -import static com.jnape.palatable.lambda.adt.Unit.UNIT; -import static com.jnape.palatable.lambda.functions.specialized.checked.Runtime.throwChecked; - -/** - * Specialized {@link Supplier} that can throw any {@link Throwable}. - * - * @param The {@link Throwable} type - * @param The return type - * @see CheckedFn1 - * @see CheckedRunnable - */ -@FunctionalInterface -public interface CheckedSupplier extends Supplier, CheckedFn1 { - - /** - * A version of {@link Supplier#get()} that can throw checked exceptions. - * - * @return the supplied result - * @throws T any exception that can be thrown by this method - */ - A checkedGet() throws T; - - /** - * Convert this {@link CheckedSupplier} to a {@link CheckedRunnable}. - * - * @return the checked runnable - */ - default CheckedRunnable toRunnable() { - return this::get; - } - - @Override - default A checkedApply(Unit unit) throws T { - return checkedGet(); - } - - /** - * {@inheritDoc} - */ - @Override - default A get() { - try { - return checkedGet(); - } catch (Throwable t) { - throw throwChecked(t); - } - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedSupplier fmap(Function f) { - return CheckedFn1.super.fmap(f).thunk(UNIT)::apply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedSupplier flatMap(Function>> f) { - return CheckedFn1.super.flatMap(f).thunk(UNIT)::apply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedSupplier discardL(Applicative> appB) { - return CheckedFn1.super.discardL(appB).thunk(UNIT)::apply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedSupplier discardR(Applicative> appB) { - return CheckedFn1.super.discardR(appB).thunk(UNIT)::apply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedSupplier zip(Applicative, Fn1> appFn) { - return CheckedFn1.super.zip(appFn).thunk(UNIT)::apply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedSupplier zip(Fn2 appFn) { - return CheckedFn1.super.zip(appFn).thunk(UNIT)::apply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedSupplier diMapR(Function fn) { - return CheckedFn1.super.diMapR(fn).thunk(UNIT)::apply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedSupplier> carry() { - return CheckedFn1.super.carry().thunk(UNIT)::apply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedSupplier andThen(Function after) { - return CheckedFn1.super.andThen(after).thunk(UNIT)::apply; - } - - /** - * Convenience static factory method for constructing a {@link CheckedSupplier} without an explicit cast or type - * attribution at the call site. - * - * @param supplier the checked supplier - * @param the inferred Throwable type - * @param the supplier return type - * @return the checked supplier - */ - static CheckedSupplier checked(CheckedSupplier supplier) { - return supplier::get; - } -} diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java b/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java index c8eb56d7c..4dd634e13 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.functor; -import java.util.function.Function; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; @@ -26,7 +27,7 @@ * @param The type of the parameter * @param The unification parameter to more tightly type-constrain Applicatives to themselves */ -public interface Applicative extends Functor { +public interface Applicative> extends Functor { /** * Lift the value b into this applicative functor. @@ -45,10 +46,26 @@ public interface Applicative extends Functor * @param the resulting applicative parameter type * @return the mapped applicative */ - Applicative zip(Applicative, App> appFn); + Applicative zip(Applicative, App> appFn); + + /** + * Given a {@link Lazy lazy} instance of this applicative over a mapping function, "zip" the two instances together + * using whatever application semantics the current applicative supports. This is useful for applicatives that + * support lazy evaluation and early termination. + * + * @param the resulting applicative parameter type + * @param lazyAppFn the lazy other applicative instance + * @return the mapped applicative + * @see com.jnape.palatable.lambda.adt.Maybe + * @see com.jnape.palatable.lambda.adt.Either + */ + default Lazy> lazyZip( + Lazy, App>> lazyAppFn) { + return lazyAppFn.fmap(this::zip); + } @Override - default Applicative fmap(Function fn) { + default Applicative fmap(Fn1 fn) { return zip(pure(fn)); } @@ -75,15 +92,4 @@ default Applicative discardL(Applicative appB) { default Applicative discardR(Applicative appB) { return appB.zip(fmap(constantly())); } - - /** - * Convenience method for coercing this applicative instance into another concrete type. Unsafe. - * - * @param the concrete applicative instance to coerce this applicative to - * @return the coerced applicative - */ - @SuppressWarnings("unchecked") - default > Concrete coerce() { - return (Concrete) this; - } } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Bifunctor.java b/src/main/java/com/jnape/palatable/lambda/functor/Bifunctor.java index 695c71a8f..bfb201242 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Bifunctor.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Bifunctor.java @@ -1,6 +1,6 @@ package com.jnape.palatable.lambda.functor; -import java.util.function.Function; +import com.jnape.palatable.lambda.functions.Fn1; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; @@ -17,7 +17,7 @@ * @see com.jnape.palatable.lambda.adt.hlist.Tuple2 */ @FunctionalInterface -public interface Bifunctor extends BoundedBifunctor { +public interface Bifunctor> extends BoundedBifunctor { /** * Covariantly map over the left parameter. @@ -26,7 +26,7 @@ public interface Bifunctor extends BoundedBifunctor< * @param fn the mapping function * @return a bifunctor over C (the new left parameter) and B (the same right parameter) */ - default Bifunctor biMapL(Function fn) { + default Bifunctor biMapL(Fn1 fn) { return biMap(fn, id()); } @@ -38,7 +38,7 @@ default Bifunctor biMapL(Function fn) { * @param fn the mapping function * @return a bifunctor over A (the same left parameter) and C (the new right parameter) */ - default Bifunctor biMapR(Function fn) { + default Bifunctor biMapR(Fn1 fn) { return biMap(id(), fn); } @@ -52,5 +52,5 @@ default Bifunctor biMapR(Function fn) { * @param rFn the right parameter mapping function * @return a bifunctor over C (the new left parameter type) and D (the new right parameter type) */ - Bifunctor biMap(Function lFn, Function rFn); + Bifunctor biMap(Fn1 lFn, Fn1 rFn); } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/BoundedBifunctor.java b/src/main/java/com/jnape/palatable/lambda/functor/BoundedBifunctor.java index 02fc7775f..057c3bd29 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/BoundedBifunctor.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/BoundedBifunctor.java @@ -1,6 +1,6 @@ package com.jnape.palatable.lambda.functor; -import java.util.function.Function; +import com.jnape.palatable.lambda.functions.Fn1; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; @@ -16,29 +16,32 @@ * @see Bifunctor */ @FunctionalInterface -public interface BoundedBifunctor { +public interface BoundedBifunctor< + A extends ContraA, + B extends ContraB, + ContraA, + ContraB, + BF extends BoundedBifunctor> { /** * Covariantly map the left parameter into a value that is covariant to ContraA. * - * @param fn the mapping function * @param the new left parameter type + * @param fn the mapping function * @return a bifunctor of C (the new parameter type) and B (the same right parameter) */ - default BoundedBifunctor biMapL( - Function fn) { + default BoundedBifunctor biMapL(Fn1 fn) { return biMap(fn, id()); } /** * Covariantly map the right parameter into a value that is covariant to ContraB. * - * @param fn the mapping function * @param the new right parameter type + * @param fn the mapping function * @return a bifunctor of A (the same left parameter) and C (the new parameter type) */ - default BoundedBifunctor biMapR( - Function fn) { + default BoundedBifunctor biMapR(Fn1 fn) { return biMap(id(), fn); } @@ -53,6 +56,6 @@ default BoundedBifunctor biMapR( * @return a bifunctor over C (the new left parameter type) and D (the new right parameter type) */ BoundedBifunctor biMap( - Function lFn, - Function rFn); + Fn1 lFn, + Fn1 rFn); } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Cartesian.java b/src/main/java/com/jnape/palatable/lambda/functor/Cartesian.java new file mode 100644 index 000000000..e3ac2783b --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functor/Cartesian.java @@ -0,0 +1,53 @@ +package com.jnape.palatable.lambda.functor; + +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn1; + +/** + * {@link Profunctor} strength in the cartesian product sense: p a b -> p (c ^ a) (c ^ b) for any type + * c. + * + * @param the type of the left parameter + * @param the type of the left parameter + * @param

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

the unification parameter + * @see com.jnape.palatable.lambda.functions.Fn1 + * @see Cartesian + */ +public interface Cocartesian> extends Profunctor { + + /** + * Choose some type C or this profunctor's carrier types. + * + * @param the choice type + * @return the cocartesian-costrengthened profunctor + */ + Cocartesian, Choice2, P> cocartesian(); + + /** + * Choose between the covariantly-positioned carrier type and the contravariantly-positioned carrier type. This can + * be used to encode partial functions a -> (_|_ v b) as total functions + * a -> (a v b). + * + * @return the profunctor with a choice + */ + default Cocartesian, P> choose() { + return this.cocartesian().contraMap(Choice2::b); + } + + /** + * {@inheritDoc} + */ + @Override + Cocartesian diMap(Fn1 lFn, Fn1 rFn); + + /** + * {@inheritDoc} + */ + @Override + default Cocartesian diMapL(Fn1 fn) { + return (Cocartesian) Profunctor.super.diMapL(fn); + } + + /** + * {@inheritDoc} + */ + @Override + default Cocartesian diMapR(Fn1 fn) { + return (Cocartesian) Profunctor.super.diMapR(fn); + } + + /** + * {@inheritDoc} + */ + @Override + default Cocartesian contraMap(Fn1 fn) { + return (Cocartesian) Profunctor.super.contraMap(fn); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Contravariant.java b/src/main/java/com/jnape/palatable/lambda/functor/Contravariant.java index 07d548d1a..c596b36b0 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Contravariant.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Contravariant.java @@ -1,20 +1,21 @@ package com.jnape.palatable.lambda.functor; -import java.util.function.Function; +import com.jnape.palatable.lambda.functions.Fn1; /** * The contravariant functor (or "co-functor"); that is, a functor that maps contravariantly (A <- B) * over its parameter. * Contravariant functors are not necessarily {@link Functor}s. *

- * For more information, read about Contravariant Functors. * * @param the type of the parameter * @param the unification parameter * @see Profunctor */ -public interface Contravariant { +public interface Contravariant> { /** * Contravariantly map A <- B. @@ -23,5 +24,5 @@ public interface Contravariant { * @param the new parameter type * @return the mapped Contravariant functor instance */ - Contravariant contraMap(Function fn); + Contravariant contraMap(Fn1 fn); } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Functor.java b/src/main/java/com/jnape/palatable/lambda/functor/Functor.java index 769aae816..ec4323641 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Functor.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Functor.java @@ -2,7 +2,7 @@ import com.jnape.palatable.lambda.functions.Fn1; -import java.util.function.Function; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Downcast.downcast; /** * An interface for the generic covariant functorial operation map over some parameter A. @@ -20,7 +20,7 @@ * @see com.jnape.palatable.lambda.adt.Either */ @FunctionalInterface -public interface Functor { +public interface Functor> { /** * Covariantly transmute this functor's parameter using the given mapping function. Generally this method is @@ -30,5 +30,15 @@ public interface Functor { * @param fn the mapping function * @return a functor over B (the new parameter type) */ - Functor fmap(Function fn); + Functor fmap(Fn1 fn); + + /** + * Convenience method for coercing this functor instance into another concrete type. Unsafe. + * + * @param the concrete functor instance to coerce this functor to + * @return the coerced functor + */ + default > Concrete coerce() { + return downcast(this); + } } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Profunctor.java b/src/main/java/com/jnape/palatable/lambda/functor/Profunctor.java index 0e7235b44..b9518d3e4 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Profunctor.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Profunctor.java @@ -1,9 +1,6 @@ package com.jnape.palatable.lambda.functor; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.lens.Lens; - -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; @@ -19,10 +16,10 @@ * @see Bifunctor * @see Contravariant * @see Fn1 - * @see Lens + * @see com.jnape.palatable.lambda.optics.Optic */ @FunctionalInterface -public interface Profunctor extends Contravariant> { +public interface Profunctor> extends Contravariant> { /** * Dually map contravariantly over the left parameter and covariantly over the right parameter. This is isomorphic @@ -34,7 +31,7 @@ public interface Profunctor extends Contravariant Profunctor diMap(Function lFn, Function rFn); + Profunctor diMap(Fn1 lFn, Fn1 rFn); /** * Contravariantly map over the left parameter. @@ -43,7 +40,7 @@ public interface Profunctor extends Contravariant Profunctor diMapL(Function fn) { + default Profunctor diMapL(Fn1 fn) { return diMap(fn, id()); } @@ -55,12 +52,15 @@ default Profunctor diMapL(Function fn) { * @param fn the mapping function * @return a profunctor over A (the same left parameter type) and C (the new right parameter type) */ - default Profunctor diMapR(Function fn) { + default Profunctor diMapR(Fn1 fn) { return diMap(id(), fn); } + /** + * {@inheritDoc} + */ @Override - default Profunctor contraMap(Function fn) { + default Profunctor contraMap(Fn1 fn) { return diMapL(fn); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Strong.java b/src/main/java/com/jnape/palatable/lambda/functor/Strong.java deleted file mode 100644 index c6b4929c2..000000000 --- a/src/main/java/com/jnape/palatable/lambda/functor/Strong.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.jnape.palatable.lambda.functor; - -import com.jnape.palatable.lambda.adt.hlist.Tuple2; - -import java.util.function.Function; - -/** - * "Strong" {@link Profunctor profunctors} are profunctors that can be "strengthened" to preserve the pairing of an - * arbitrary type under dimap (p a b -> p (c, a) (c, b) for any type c). - * - * @param the type of the left parameter - * @param the type of the left parameter - * @param the unification parameter - * @see com.jnape.palatable.lambda.functions.Fn1 - */ -public interface Strong extends Profunctor { - - /** - * Pair some type C to this profunctor's carrier types. - * - * @param the paired type - * @return the strengthened profunctor - */ - Strong, Tuple2, S> strengthen(); - - /** - * Pair the covariantly-positioned carrier type with the contravariantly-positioned carrier type. This can be - * thought of as "carrying" or "inspecting" the left parameter. - * - * @return the profunctor with the first parameter carried - */ - default Strong, S> carry() { - return this.strengthen().contraMap(Tuple2::fill); - } - - @Override - Strong diMap(Function lFn, Function rFn); - - @Override - default Strong diMapL(Function fn) { - return (Strong) Profunctor.super.diMapL(fn); - } - - @Override - default Strong diMapR(Function fn) { - return (Strong) Profunctor.super.diMapR(fn); - } - - @Override - default Strong contraMap(Function fn) { - return (Strong) Profunctor.super.contraMap(fn); - } -} diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java index 40a732247..a9a50eb91 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java @@ -1,9 +1,11 @@ package com.jnape.palatable.lambda.functor.builtin; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import java.util.Objects; -import java.util.function.Function; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Upcast.upcast; /** * A functor representing the type-level composition of two {@link Applicative} functors; useful for preserving nested @@ -13,7 +15,8 @@ * @param The inner applicative * @param The carrier type */ -public final class Compose implements Applicative> { +public final class Compose, G extends Applicative, A> implements + Applicative> { private final Applicative, F> fga; @@ -21,30 +24,65 @@ public Compose(Applicative, F> fga) { this.fga = fga; } + @SuppressWarnings("RedundantTypeArguments") public , FGA extends Applicative> FGA getCompose() { - return fga.fmap(Applicative::coerce).coerce(); + return fga.fmap(Applicative::coerce).coerce(); } + /** + * {@inheritDoc} + */ @Override - public Compose fmap(Function fn) { + public Compose fmap(Fn1 fn) { return new Compose<>(fga.fmap(g -> g.fmap(fn))); } + /** + * {@inheritDoc} + */ @Override public Compose pure(B b) { return new Compose<>(fga.fmap(g -> g.pure(b))); } + /** + * {@inheritDoc} + */ @Override - public Compose zip(Applicative, Compose> appFn) { - return new Compose<>(fga.zip(appFn.>>coerce().getCompose().fmap(gFn -> g -> g.zip(gFn)))); + public Compose zip(Applicative, Compose> appFn) { + return new Compose<>(fga.zip(appFn.>>coerce() + .getCompose().fmap(gFn -> g -> g.zip(gFn)))); + } + + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, Compose>> lazyAppFn) { + @SuppressWarnings("RedundantTypeArguments") + Lazy, G>, F>> lazyAppFnCoerced = + lazyAppFn + .>>fmap( + Applicative, Compose>::coerce) + .fmap(Compose>::getCompose); + + return fga.>fmap(upcast()) + .>lazyZip(lazyAppFnCoerced.fmap(fgf -> fgf.fmap(gf -> ga -> ga.zip(gf)))) + .fmap(Compose::new); } + /** + * {@inheritDoc} + */ @Override public Compose discardL(Applicative> appB) { return Applicative.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Compose discardR(Applicative> appB) { return Applicative.super.discardR(appB).coerce(); diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java index 6de15b769..73e974ede 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java @@ -1,12 +1,12 @@ package com.jnape.palatable.lambda.functor.builtin; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; -import java.util.function.Function; /** * A (surprisingly useful) functor over some phantom type B, retaining a value of type A that @@ -17,7 +17,10 @@ * @param the left parameter type, and the type of the stored value * @param the right (phantom) parameter type */ -public final class Const implements Monad>, Bifunctor, Traversable> { +public final class Const implements + Monad>, + Bifunctor>, + Traversable> { private final A a; @@ -43,7 +46,7 @@ public A runConst() { * @return a Const over A (the same value) and C (the new phantom parameter) */ @Override - public Const fmap(Function fn) { + public Const fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } @@ -53,71 +56,81 @@ public Const pure(C c) { return (Const) this; } + /** + * {@inheritDoc} + */ @Override - public Const zip(Applicative, Const> appFn) { + public Const zip(Applicative, Const> appFn) { return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, Const>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); + } + + /** + * {@inheritDoc} + */ @Override public Const discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Const discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") - public Const flatMap(Function>> f) { + public Const flatMap(Fn1>> f) { return (Const) this; } + /** + * {@inheritDoc} + */ @Override - public >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public , TravB extends Traversable>, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, + Fn1 pure) { return pure.apply(coerce()); } /** - * Covariantly map over the left parameter type (the value). - * - * @param fn the mapping function - * @param the new left parameter type (the value) - * @return a Const over Z (the new value) and B (the same phantom parameter) + * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") - public Const biMapL(Function fn) { - return (Const) Bifunctor.super.biMapL(fn); + public Const biMapL(Fn1 fn) { + return (Const) Bifunctor.super.biMapL(fn); } /** - * Covariantly map over the right parameter (phantom) type. - * - * @param fn the mapping function - * @param the new right parameter (phantom) type - * @return a Const over A (the same value) and C (the new phantom parameter) + * {@inheritDoc} */ @Override @SuppressWarnings("unchecked") - public Const biMapR(Function fn) { + public Const biMapR(Fn1 fn) { return (Const) Bifunctor.super.biMapR(fn); } /** - * Bifunctor's biMap, specialized for Const. - * - * @param lFn the left parameter mapping function - * @param rFn the right parameter mapping function - * @param the new left parameter type - * @param the new right parameter type - * @return a Const over C (the new value) and D (the new phantom parameter) + * {@inheritDoc} */ @Override - public Const biMap(Function lFn, - Function rFn) { + public Const biMap(Fn1 lFn, + Fn1 rFn) { return new Const<>(lFn.apply(a)); } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Exchange.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Exchange.java index 6a317784c..f04050368 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Exchange.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Exchange.java @@ -1,9 +1,8 @@ package com.jnape.palatable.lambda.functor.builtin; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Profunctor; -import com.jnape.palatable.lambda.lens.Iso; - -import java.util.function.Function; +import com.jnape.palatable.lambda.optics.Iso; /** * A profunctor used to extract the isomorphic functions an {@link Iso} is composed of. @@ -14,40 +13,62 @@ * @param the larger viewed value of an {@link Iso} */ public final class Exchange implements Profunctor> { - private final Function sa; - private final Function bt; + private final Fn1 sa; + private final Fn1 bt; - public Exchange(Function sa, Function bt) { + public Exchange(Fn1 sa, Fn1 bt) { this.sa = sa; this.bt = bt; } - public Function sa() { + /** + * Extract the mapping S -> A. + * + * @return an {@link Fn1}<S, A> + */ + public Fn1 sa() { return sa; } - public Function bt() { + /** + * Extract the mapping B -> T. + * + * @return an {@link Fn1}<B, T> + */ + public Fn1 bt() { return bt; } + /** + * {@inheritDoc} + */ @Override - public Exchange diMap(Function lFn, - Function rFn) { - return new Exchange<>(lFn.andThen(sa), bt.andThen(rFn)); + public Exchange diMap(Fn1 lFn, + Fn1 rFn) { + return new Exchange<>(lFn.fmap(sa), bt.fmap(rFn)); } + /** + * {@inheritDoc} + */ @Override - public Exchange diMapL(Function fn) { + public Exchange diMapL(Fn1 fn) { return (Exchange) Profunctor.super.diMapL(fn); } + /** + * {@inheritDoc} + */ @Override - public Exchange diMapR(Function fn) { + public Exchange diMapR(Fn1 fn) { return (Exchange) Profunctor.super.diMapR(fn); } + /** + * {@inheritDoc} + */ @Override - public Exchange contraMap(Function fn) { + public Exchange contraMap(Fn1 fn) { return (Exchange) Profunctor.super.contraMap(fn); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java index 68e223c40..dba617294 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java @@ -1,18 +1,18 @@ package com.jnape.palatable.lambda.functor.builtin; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; -import java.util.function.Function; /** * A functor over some value of type A that can be mapped over and retrieved later. * * @param the value type */ -public final class Identity implements Monad, Traversable { +public final class Identity implements Monad>, Traversable> { private final A a; @@ -33,7 +33,7 @@ public A runIdentity() { * {@inheritDoc} */ @Override - public Identity flatMap(Function> f) { + public Identity flatMap(Fn1>> f) { return f.apply(runIdentity()).coerce(); } @@ -41,34 +41,59 @@ public Identity flatMap(Function> * {@inheritDoc} */ @Override - public Identity fmap(Function fn) { + public Identity fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override public Identity pure(B b) { return new Identity<>(b); } + /** + * {@inheritDoc} + */ @Override - public Identity zip(Applicative, Identity> appFn) { - return new Identity<>(appFn.>>coerce().runIdentity().apply(a)); + public Identity zip(Applicative, Identity> appFn) { + return new Identity<>(appFn.>>coerce().runIdentity().apply(a)); } + /** + * {@inheritDoc} + */ @Override - public Identity discardL(Applicative appB) { + public Lazy> lazyZip( + Lazy, Identity>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); + } + + /** + * {@inheritDoc} + */ + @Override + public Identity discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override - public Identity discardR(Applicative appB) { + public Identity discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") - public , AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public , TravB extends Traversable>, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, + Fn1 pure) { return (AppTrav) fn.apply(runIdentity()).fmap(Identity::new); } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java new file mode 100644 index 000000000..fff6acc72 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java @@ -0,0 +1,179 @@ +package com.jnape.palatable.lambda.functor.builtin; + +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn0; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.traversable.Traversable; + +import java.util.LinkedList; +import java.util.Objects; + +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; +import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.recurse; +import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.terminate; +import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline; + +/** + * A {@link Monad} representing a lazily-computed value. Stack-safe. + * + * @param the value type + */ +public abstract class Lazy implements Monad>, Traversable> { + + private Lazy() { + } + + /** + * Returns the value represented by this lazy computation. + * + * @return the value + */ + public abstract A value(); + + /** + * {@inheritDoc} + */ + @Override + public Lazy flatMap(Fn1>> f) { + @SuppressWarnings("unchecked") Lazy source = (Lazy) this; + @SuppressWarnings({"unchecked", "RedundantCast"}) + Fn1> flatMap = (Fn1>) (Object) f; + return new Compose<>(source, flatMap); + } + + /** + * {@inheritDoc} + */ + @Override + @SuppressWarnings("unchecked") + public , TravB extends Traversable>, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, + Fn1 pure) { + return fn.apply(value()).fmap(b -> (TravB) lazy(b)).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public final Lazy pure(B b) { + return lazy(b); + } + + /** + * {@inheritDoc} + */ + @Override + public final Lazy fmap(Fn1 fn) { + return Monad.super.fmap(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public Lazy zip(Applicative, Lazy> appFn) { + return Monad.super.zip(appFn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public final Lazy discardL(Applicative> appB) { + return Monad.super.discardL(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public final Lazy discardR(Applicative> appB) { + return Monad.super.discardR(appB).coerce(); + } + + @Override + public boolean equals(Object other) { + return other instanceof Lazy && Objects.equals(value(), ((Lazy) other).value()); + } + + @Override + public int hashCode() { + return Objects.hash(value()); + } + + @Override + public String toString() { + return "Lazy{value=" + value() + "}"; + } + + /** + * Lift a pure value into a lazy computation. + * + * @param value the value + * @param the value type + * @return the new {@link Lazy} + */ + public static Lazy lazy(A value) { + return lazy(() -> value); + } + + /** + * Wrap a computation in a lazy computation. + * + * @param the value type + * @param fn0 the computation + * @return the new {@link Lazy} + */ + public static Lazy lazy(Fn0 fn0) { + return new Later<>(fn0); + } + + private static final class Later extends Lazy { + private final Fn0 fn0; + + private Later(Fn0 fn0) { + this.fn0 = fn0; + } + + @Override + public A value() { + return fn0.apply(); + } + } + + private static final class Compose extends Lazy { + private final Lazy source; + private final Fn1> flatMap; + + private Compose(Lazy source, + Fn1> flatMap) { + this.source = source; + this.flatMap = flatMap; + } + + @Override + public A value() { + @SuppressWarnings("unchecked") Tuple2, LinkedList>>> tuple = + tuple((Lazy) this, new LinkedList<>()); + @SuppressWarnings("unchecked") + A a = (A) trampoline(into((source, flatMaps) -> { + if (source instanceof Compose) { + Compose nested = (Compose) source; + flatMaps.push(nested.flatMap); + return recurse(tuple(nested.source, flatMaps)); + } + + if (flatMaps.isEmpty()) + return terminate(source.value()); + + return recurse(tuple(flatMaps.pop().apply(source.value()), flatMaps)); + }), tuple); + + return a; + } + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Market.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Market.java new file mode 100644 index 000000000..f1a4b3243 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Market.java @@ -0,0 +1,134 @@ +package com.jnape.palatable.lambda.functor.builtin; + +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.adt.choice.Choice2; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.Cocartesian; +import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.optics.Prism; + +import static com.jnape.palatable.lambda.adt.Either.left; +import static com.jnape.palatable.lambda.adt.choice.Choice2.a; +import static com.jnape.palatable.lambda.adt.choice.Choice2.b; +import static com.jnape.palatable.lambda.functions.Fn1.fn1; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; + +/** + * A profunctor used to extract the isomorphic functions a {@link Prism} is composed of. + * + * @param the output that might fail to be produced + * @param the input that guarantees its output + * @param the input that might fail to map to its output + * @param the guaranteed output + */ +public final class Market implements + Monad>, + Cocartesian> { + + private final Fn1 bt; + private final Fn1> sta; + + public Market(Fn1 bt, Fn1> sta) { + this.bt = fn1(bt); + this.sta = fn1(sta); + } + + /** + * Extract the mapping B -> T. + * + * @return a {@link Fn1}<B, T> + */ + public Fn1 bt() { + return bt; + } + + /** + * Extract the mapping S -> {@link Either}<T, A>. + * + * @return a {@link Fn1}<S, {@link Either}<T, A>> + */ + public Fn1> sta() { + return sta; + } + + /** + * {@inheritDoc} + */ + @Override + public Market pure(U u) { + return new Market<>(constantly(u), constantly(left(u))); + } + + /** + * {@inheritDoc} + */ + @Override + public Market flatMap(Fn1>> f) { + return new Market<>(b -> f.apply(bt().apply(b)).>coerce().bt().apply(b), + s -> sta().apply(s).invert() + .flatMap(t -> f.apply(t).>coerce().sta() + .apply(s).invert()).invert()); + } + + /** + * {@inheritDoc} + */ + @Override + public Market zip(Applicative, Market> appFn) { + Market> marketF = appFn.coerce(); + return new Market<>(b -> marketF.bt().apply(b).apply(bt().apply(b)), + s -> sta().apply(s).invert().zip(marketF.sta().apply(s).invert()).invert()); + } + + /** + * {@inheritDoc} + */ + @Override + public Market fmap(Fn1 fn) { + return diMapR(fn::apply); + } + + /** + * {@inheritDoc} + */ + @Override + public Market, Choice2> cocartesian() { + return new Market<>(bt.fmap(Choice2::b), + cs -> cs.fmap(sta).match(c -> left(a(c)), + tOrA -> tOrA.match(t -> left(b(t)), Either::right))); + } + + /** + * {@inheritDoc} + */ + @Override + public Market diMap(Fn1 lFn, + Fn1 rFn) { + return new Market<>(bt.fmap(rFn), sta.diMapL(lFn).diMapR(c -> c.biMapL(rFn))); + } + + /** + * {@inheritDoc} + */ + @Override + public Market diMapL(Fn1 fn) { + return (Market) Cocartesian.super.diMapL(fn); + } + + /** + * {@inheritDoc} + */ + @Override + public Market diMapR(Fn1 fn) { + return (Market) Cocartesian.super.diMapR(fn); + } + + /** + * {@inheritDoc} + */ + @Override + public Market contraMap(Fn1 fn) { + return (Market) Cocartesian.super.contraMap(fn); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/State.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/State.java new file mode 100644 index 000000000..ed3f17470 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/State.java @@ -0,0 +1,213 @@ +package com.jnape.palatable.lambda.functor.builtin; + +import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.adt.hlist.HList; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.adt.product.Product2; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.monad.Monad; + +import static com.jnape.palatable.lambda.adt.Unit.UNIT; +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Both.both; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; + +/** + * The state {@link Monad}, useful for iteratively building up state and state-contextualized result. + *

+ * For more information, read about the + * state monad. + * + * @param the state type + * @param the result type + */ +public final class State implements Monad> { + + private final Fn1> stateFn; + + private State(Fn1> stateFn) { + this.stateFn = stateFn; + } + + /** + * Run the stateful computation, returning a {@link Tuple2} of the result and the final state. + * + * @param s the initial state + * @return a {@link Tuple2} of the result and the final state. + */ + public Tuple2 run(S s) { + return stateFn.apply(s).into(HList::tuple); + } + + /** + * Run the stateful computation, returning the result. + * + * @param s the initial state + * @return the result + */ + public A eval(S s) { + return run(s)._1(); + } + + /** + * Run the stateful computation, returning the final state. + * + * @param s the initial state + * @return the final state + */ + public S exec(S s) { + return run(s)._2(); + } + + /** + * Map both the result and the final state to a new result and final state. + * + * @param fn the mapping function + * @param the potentially new final state type + * @return the mapped {@link State} + */ + public State mapState(Fn1, ? extends Product2> fn) { + return state(s -> fn.apply(run(s))); + } + + /** + * Map the final state to a new final state using the provided function. + * + * @param fn the state-mapping function + * @return the mapped {@link State} + */ + public State withState(Fn1 fn) { + return state(s -> run(fn.apply(s))); + } + + /** + * {@inheritDoc} + */ + @Override + public State flatMap(Fn1>> f) { + return state(s -> run(s).into((a, s2) -> f.apply(a).>coerce().run(s2))); + } + + /** + * {@inheritDoc} + */ + @Override + public State pure(B b) { + return state(s -> tuple(b, s)); + } + + /** + * {@inheritDoc} + */ + @Override + public State fmap(Fn1 fn) { + return Monad.super.fmap(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public State zip(Applicative, State> appFn) { + return Monad.super.zip(appFn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, State>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); + } + + /** + * {@inheritDoc} + */ + @Override + public State discardR(Applicative> appB) { + return Monad.super.discardR(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public State discardL(Applicative> appB) { + return Monad.super.discardL(appB).coerce(); + } + + /** + * Create a {@link State} that simply returns back the initial state as both the result and the final state + * + * @param the state and result type + * @return the new {@link State} instance + */ + @SuppressWarnings("RedundantTypeArguments") + public static State get() { + return new State<>(Tuple2::fill); + } + + /** + * Create a {@link State} that ignores its initial state, returning a {@link Unit} result and s as its + * final state. + * + * @param s the final state + * @param the state type + * @return the new {@link State} instance + */ + public static State put(S s) { + return new State<>(constantly(tuple(UNIT, s))); + } + + /** + * Create a {@link State} that maps its initial state into its result, but leaves the initial state unchanged. + * + * @param fn the mapping function + * @param the state type + * @param the result type + * @return the new {@link State} instance + */ + public static State gets(Fn1 fn) { + return state(both(fn, id())); + } + + /** + * Create a {@link State} that maps its initial state into its final state, returning a {@link Unit} result type. + * + * @param fn the mapping function + * @param the state type + * @return the new {@link State} instance + */ + public static State modify(Fn1 fn) { + return state(both(constantly(UNIT), fn)); + } + + /** + * Create a {@link State} from stateFn, a function that maps an initial state into a result and a final + * state. + * + * @param stateFn the state function + * @param the state type + * @param the result type + * @return the new {@link State} instance + */ + public static State state(Fn1> stateFn) { + return new State<>(stateFn.fmap(into(HList::tuple))); + } + + /** + * Create a {@link State} that returns a as its result and its initial state as its final state. + * + * @param a the result + * @param the state type + * @param the result type + * @return the new {@link State} instance + */ + public static State state(A a) { + return gets(constantly(a)); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Tagged.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Tagged.java new file mode 100644 index 000000000..c601e6d65 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Tagged.java @@ -0,0 +1,121 @@ +package com.jnape.palatable.lambda.functor.builtin; + +import com.jnape.palatable.lambda.adt.choice.Choice2; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.Cocartesian; +import com.jnape.palatable.lambda.monad.Monad; + +import static com.jnape.palatable.lambda.adt.choice.Choice2.b; + +/** + * Like {@link Const}, but the phantom parameter is in the contravariant position, and the value is in covariant + * position. + * + * @param the phantom type + * @param the value type + */ +public final class Tagged implements Monad>, Cocartesian> { + private final B b; + + public Tagged(B b) { + this.b = b; + } + + /** + * Extract the contained value. + * + * @return the value + */ + public B unTagged() { + return b; + } + + /** + * {@inheritDoc} + */ + @Override + public Tagged flatMap(Fn1>> f) { + return f.apply(b).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public Tagged pure(C c) { + return new Tagged<>(c); + } + + /** + * {@inheritDoc} + */ + @Override + public Tagged fmap(Fn1 fn) { + return Monad.super.fmap(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public Tagged zip(Applicative, Tagged> appFn) { + return Monad.super.zip(appFn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public Tagged discardL(Applicative> appB) { + return Monad.super.discardL(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public Tagged discardR(Applicative> appB) { + return Monad.super.discardR(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public Tagged, Choice2> cocartesian() { + return new Tagged<>(b(b)); + } + + /** + * {@inheritDoc} + */ + @Override + public Tagged diMap(Fn1 lFn, Fn1 rFn) { + return new Tagged<>(rFn.apply(b)); + } + + /** + * {@inheritDoc} + */ + @Override + public Tagged diMapL(Fn1 fn) { + return (Tagged) Cocartesian.super.diMapL(fn); + } + + /** + * {@inheritDoc} + */ + @Override + public Tagged diMapR(Fn1 fn) { + return (Tagged) Cocartesian.super.diMapR(fn); + } + + /** + * {@inheritDoc} + */ + @Override + public Tagged contraMap(Fn1 fn) { + return (Tagged) Cocartesian.super.contraMap(fn); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/Runtime.java b/src/main/java/com/jnape/palatable/lambda/internal/Runtime.java similarity index 60% rename from src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/Runtime.java rename to src/main/java/com/jnape/palatable/lambda/internal/Runtime.java index 1546e811b..a280744fe 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/Runtime.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/Runtime.java @@ -1,6 +1,9 @@ -package com.jnape.palatable.lambda.functions.specialized.checked; +package com.jnape.palatable.lambda.internal; -class Runtime { +public final class Runtime { + + private Runtime() { + } @SuppressWarnings("unchecked") public static RuntimeException throwChecked(Throwable t) throws T { diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/CombinatorialIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/CombinatorialIterator.java similarity index 96% rename from src/main/java/com/jnape/palatable/lambda/iteration/CombinatorialIterator.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/CombinatorialIterator.java index 219582f4a..11922226a 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/CombinatorialIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/CombinatorialIterator.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import com.jnape.palatable.lambda.adt.hlist.Tuple2; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/ConcatenatingIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ConcatenatingIterable.java similarity index 94% rename from src/main/java/com/jnape/palatable/lambda/iteration/ConcatenatingIterable.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/ConcatenatingIterable.java index f7ae08023..594be70b2 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/ConcatenatingIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ConcatenatingIterable.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import java.util.Iterator; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/ConsingIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ConsingIterator.java similarity index 75% rename from src/main/java/com/jnape/palatable/lambda/iteration/ConsingIterator.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/ConsingIterator.java index d35d92c0b..b560974bb 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/ConsingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ConsingIterator.java @@ -1,15 +1,16 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; + +import com.jnape.palatable.lambda.functions.Fn0; import java.util.Iterator; import java.util.NoSuchElementException; -import java.util.function.Supplier; public final class ConsingIterator implements Iterator { - private final A head; - private final Supplier> asSupplier; - private Iterator asIterator; - private boolean iteratedHead; + private final A head; + private final Fn0> asSupplier; + private Iterator asIterator; + private boolean iteratedHead; public ConsingIterator(A head, Iterable as) { this.head = head; @@ -23,7 +24,7 @@ public boolean hasNext() { return true; if (asIterator == null) - asIterator = asSupplier.get(); + asIterator = asSupplier.apply(); return asIterator.hasNext(); } diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/CyclicIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/CyclicIterable.java similarity index 88% rename from src/main/java/com/jnape/palatable/lambda/iteration/CyclicIterable.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/CyclicIterable.java index 6d08dbcf2..3218892b2 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/CyclicIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/CyclicIterable.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import java.util.Iterator; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/CyclicIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/CyclicIterator.java similarity index 94% rename from src/main/java/com/jnape/palatable/lambda/iteration/CyclicIterator.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/CyclicIterator.java index 2705ffa06..827652a44 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/CyclicIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/CyclicIterator.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import java.util.ArrayList; import java.util.Iterator; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/DistinctIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/DistinctIterable.java similarity index 91% rename from src/main/java/com/jnape/palatable/lambda/iteration/DistinctIterable.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/DistinctIterable.java index 447b76168..19758a6df 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/DistinctIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/DistinctIterable.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import java.util.HashMap; import java.util.Iterator; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/DroppingIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/DroppingIterable.java similarity index 91% rename from src/main/java/com/jnape/palatable/lambda/iteration/DroppingIterable.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/DroppingIterable.java index b545a296f..1d9534b17 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/DroppingIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/DroppingIterable.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import java.util.Iterator; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/DroppingIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/DroppingIterator.java similarity index 93% rename from src/main/java/com/jnape/palatable/lambda/iteration/DroppingIterator.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/DroppingIterator.java index 5f69eb643..5b758695b 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/DroppingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/DroppingIterator.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import java.util.Iterator; import java.util.NoSuchElementException; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/FilteringIterable.java similarity index 55% rename from src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterable.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/FilteringIterable.java index 1b9f315ff..7accde2f8 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/FilteringIterable.java @@ -1,19 +1,20 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; + +import com.jnape.palatable.lambda.functions.Fn1; import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn2.All.all; import static java.util.Collections.singletonList; public final class FilteringIterable implements Iterable { - private final List> predicates; - private final Iterable as; + private final List> predicates; + private final Iterable as; - public FilteringIterable(Function predicate, Iterable as) { - List> predicates = new ArrayList<>(singletonList(predicate)); + public FilteringIterable(Fn1 predicate, Iterable as) { + List> predicates = new ArrayList<>(singletonList(predicate)); while (as instanceof FilteringIterable) { FilteringIterable nested = (FilteringIterable) as; predicates.addAll(0, nested.predicates); @@ -25,7 +26,7 @@ public FilteringIterable(Function predicate, Itera @Override public Iterator iterator() { - Function metaPredicate = a -> all(p -> p.apply(a), predicates); + Fn1 metaPredicate = a -> all(p -> p.apply(a), predicates); return new FilteringIterator<>(metaPredicate, as.iterator()); } } diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/FilteringIterator.java similarity index 70% rename from src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterator.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/FilteringIterator.java index 5b9358c01..4a9346d40 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/FilteringIterator.java @@ -1,15 +1,16 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; + +import com.jnape.palatable.lambda.functions.Fn1; import java.util.Iterator; import java.util.NoSuchElementException; -import java.util.function.Function; public final class FilteringIterator extends ImmutableIterator { - private final Function predicate; - private final RewindableIterator rewindableIterator; + private final Fn1 predicate; + private final RewindableIterator rewindableIterator; - public FilteringIterator(Function predicate, Iterator iterator) { + public FilteringIterator(Fn1 predicate, Iterator iterator) { this.predicate = predicate; rewindableIterator = new RewindableIterator<>(iterator); } diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/FlatteningIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/FlatteningIterator.java similarity index 92% rename from src/main/java/com/jnape/palatable/lambda/iteration/FlatteningIterator.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/FlatteningIterator.java index 40458cd48..f02759374 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/FlatteningIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/FlatteningIterator.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import java.util.Iterator; import java.util.NoSuchElementException; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/GroupingIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/GroupingIterator.java similarity index 92% rename from src/main/java/com/jnape/palatable/lambda/iteration/GroupingIterator.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/GroupingIterator.java index fdaf95ebe..08d2f8c3f 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/GroupingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/GroupingIterator.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import java.util.ArrayList; import java.util.Iterator; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/ImmutableIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ImmutableIterator.java similarity index 81% rename from src/main/java/com/jnape/palatable/lambda/iteration/ImmutableIterator.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/ImmutableIterator.java index 7252d2313..cc41f275d 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/ImmutableIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ImmutableIterator.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import java.util.Iterator; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/ImmutableQueue.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ImmutableQueue.java similarity index 94% rename from src/main/java/com/jnape/palatable/lambda/iteration/ImmutableQueue.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/ImmutableQueue.java index 5a734a88c..1b683c870 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/ImmutableQueue.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ImmutableQueue.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import com.jnape.palatable.lambda.adt.Maybe; @@ -45,11 +45,11 @@ public A next() { @SuppressWarnings("unchecked") public static ImmutableQueue empty() { - return Empty.INSTANCE; + return (ImmutableQueue) Empty.INSTANCE; } private static final class Empty extends ImmutableQueue { - private static final Empty INSTANCE = new Empty(); + private static final Empty INSTANCE = new Empty<>(); @Override ImmutableQueue pushFront(A a) { diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/ImmutableStack.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ImmutableStack.java similarity index 91% rename from src/main/java/com/jnape/palatable/lambda/iteration/ImmutableStack.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/ImmutableStack.java index 619619efb..a337ec21b 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/ImmutableStack.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ImmutableStack.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import com.jnape.palatable.lambda.adt.Maybe; @@ -42,11 +42,11 @@ public A next() { @SuppressWarnings("unchecked") public static ImmutableStack empty() { - return Empty.INSTANCE; + return (ImmutableStack) Empty.INSTANCE; } private static final class Empty extends ImmutableStack { - private static final Empty INSTANCE = new Empty(); + private static final Empty INSTANCE = new Empty<>(); @Override Maybe head() { diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/InfiniteIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/InfiniteIterator.java similarity index 73% rename from src/main/java/com/jnape/palatable/lambda/iteration/InfiniteIterator.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/InfiniteIterator.java index 88b7c640d..f136da18d 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/InfiniteIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/InfiniteIterator.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; public abstract class InfiniteIterator extends ImmutableIterator { @Override diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/InitIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/InitIterator.java similarity index 92% rename from src/main/java/com/jnape/palatable/lambda/iteration/InitIterator.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/InitIterator.java index 0b1daa4e9..31eed515f 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/InitIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/InitIterator.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import java.util.Iterator; import java.util.NoSuchElementException; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/IterationInterruptedException.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/IterationInterruptedException.java similarity index 82% rename from src/main/java/com/jnape/palatable/lambda/iteration/IterationInterruptedException.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/IterationInterruptedException.java index 69b26f335..c52797198 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/IterationInterruptedException.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/IterationInterruptedException.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import com.jnape.palatable.lambda.functions.builtin.fn4.RateLimit; @@ -9,6 +9,7 @@ * * @see RateLimit */ +@SuppressWarnings("serial") public final class IterationInterruptedException extends RuntimeException { public IterationInterruptedException(InterruptedException cause) { diff --git a/src/main/java/com/jnape/palatable/lambda/internal/iteration/MappingIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/MappingIterable.java new file mode 100644 index 000000000..3d2f1ba65 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/MappingIterable.java @@ -0,0 +1,35 @@ +package com.jnape.palatable.lambda.internal.iteration; + +import com.jnape.palatable.lambda.functions.Fn1; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft; +import static java.util.Collections.singletonList; + +public final class MappingIterable implements Iterable { + private final Iterable as; + private final List> mappers; + + @SuppressWarnings("unchecked") + public MappingIterable(Fn1 fn, Iterable as) { + List> mappers = new ArrayList<>(singletonList(fn)); + while (as instanceof MappingIterable) { + MappingIterable nested = (MappingIterable) as; + as = (Iterable) nested.as; + mappers.addAll(0, nested.mappers); + } + this.as = as; + this.mappers = mappers; + } + + @Override + @SuppressWarnings("unchecked") + public Iterator iterator() { + Fn1 fnComposedOnTheHeap = a -> foldLeft((x, fn) -> ((Fn1) fn).apply(x), + a, mappers); + return new MappingIterator<>((Fn1) fnComposedOnTheHeap, as.iterator()); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/MappingIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/MappingIterator.java similarity index 53% rename from src/main/java/com/jnape/palatable/lambda/iteration/MappingIterator.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/MappingIterator.java index 0d336fa89..6fb64fd90 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/MappingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/MappingIterator.java @@ -1,14 +1,15 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; + +import com.jnape.palatable.lambda.functions.Fn1; import java.util.Iterator; -import java.util.function.Function; public final class MappingIterator extends ImmutableIterator { - private final Function function; - private final Iterator iterator; + private final Fn1 function; + private final Iterator iterator; - public MappingIterator(Function function, Iterator iterator) { + public MappingIterator(Fn1 function, Iterator iterator) { this.function = function; this.iterator = iterator; } diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterable.java similarity index 57% rename from src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterable.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterable.java index bd3aa87b6..d87cf0e09 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterable.java @@ -1,20 +1,20 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; + +import com.jnape.palatable.lambda.functions.Fn1; import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn2.Any.any; import static java.util.Collections.singletonList; public final class PredicatedDroppingIterable implements Iterable { - private final List> predicates; - private final Iterable as; - - public PredicatedDroppingIterable(Function predicate, Iterable as) { - List> predicates = new ArrayList<>(singletonList(predicate)); + private final List> predicates; + private final Iterable as; + public PredicatedDroppingIterable(Fn1 predicate, Iterable as) { + List> predicates = new ArrayList<>(singletonList(predicate)); while (as instanceof PredicatedDroppingIterable) { PredicatedDroppingIterable nested = (PredicatedDroppingIterable) as; as = nested.as; @@ -26,7 +26,7 @@ public PredicatedDroppingIterable(Function predica @Override public Iterator iterator() { - Function metaPredicate = a -> any(p -> p.apply(a), predicates); + Fn1 metaPredicate = a -> any(p -> p.apply(a), predicates); return new PredicatedDroppingIterator<>(metaPredicate, as.iterator()); } } diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterator.java similarity index 67% rename from src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterator.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterator.java index 7fe16c64b..7add62a45 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterator.java @@ -1,15 +1,16 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; + +import com.jnape.palatable.lambda.functions.Fn1; import java.util.Iterator; import java.util.NoSuchElementException; -import java.util.function.Function; public final class PredicatedDroppingIterator extends ImmutableIterator { - private final Function predicate; - private final RewindableIterator rewindableIterator; - private boolean finishedDropping; + private final Fn1 predicate; + private final RewindableIterator rewindableIterator; + private boolean finishedDropping; - public PredicatedDroppingIterator(Function predicate, Iterator asIterator) { + public PredicatedDroppingIterator(Fn1 predicate, Iterator asIterator) { this.predicate = predicate; rewindableIterator = new RewindableIterator<>(asIterator); finishedDropping = false; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedTakingIterable.java similarity index 56% rename from src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterable.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedTakingIterable.java index 14201849d..de9c7682e 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedTakingIterable.java @@ -1,19 +1,20 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; + +import com.jnape.palatable.lambda.functions.Fn1; import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn2.All.all; import static java.util.Collections.singletonList; public final class PredicatedTakingIterable implements Iterable { - private final List> predicates; - private final Iterable as; + private final List> predicates; + private final Iterable as; - public PredicatedTakingIterable(Function predicate, Iterable as) { - List> predicates = new ArrayList<>(singletonList(predicate)); + public PredicatedTakingIterable(Fn1 predicate, Iterable as) { + List> predicates = new ArrayList<>(singletonList(predicate)); while (as instanceof PredicatedTakingIterable) { PredicatedTakingIterable nested = (PredicatedTakingIterable) as; predicates.addAll(0, nested.predicates); @@ -25,7 +26,7 @@ public PredicatedTakingIterable(Function predicate @Override public Iterator iterator() { - Function metaPredicate = a -> all(p -> p.apply(a), predicates); + Fn1 metaPredicate = a -> all(p -> p.apply(a), predicates); return new PredicatedTakingIterator<>(metaPredicate, as.iterator()); } } diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedTakingIterator.java similarity index 67% rename from src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterator.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedTakingIterator.java index 370ef1e84..9760450b0 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedTakingIterator.java @@ -1,16 +1,16 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; + +import com.jnape.palatable.lambda.functions.Fn1; import java.util.Iterator; import java.util.NoSuchElementException; -import java.util.function.Function; public final class PredicatedTakingIterator extends ImmutableIterator { - private final Function predicate; - private final RewindableIterator rewindableIterator; - private boolean stillTaking; + private final Fn1 predicate; + private final RewindableIterator rewindableIterator; + private boolean stillTaking; - public PredicatedTakingIterator(Function predicate, - Iterator asIterator) { + public PredicatedTakingIterator(Fn1 predicate, Iterator asIterator) { this.predicate = predicate; rewindableIterator = new RewindableIterator<>(asIterator); stillTaking = true; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/PrependingIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/PrependingIterator.java similarity index 93% rename from src/main/java/com/jnape/palatable/lambda/iteration/PrependingIterator.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/PrependingIterator.java index 53755c0f2..8914c2aca 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/PrependingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/PrependingIterator.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import java.util.Iterator; import java.util.NoSuchElementException; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/RateLimitingIterable.java similarity index 66% rename from src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterable.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/RateLimitingIterable.java index 27427b2cb..3a7c856d4 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/RateLimitingIterable.java @@ -1,20 +1,20 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import com.jnape.palatable.lambda.adt.hlist.Tuple3; +import com.jnape.palatable.lambda.functions.Fn0; import java.time.Duration; import java.time.Instant; import java.util.HashSet; import java.util.Iterator; import java.util.Set; -import java.util.function.Supplier; public final class RateLimitingIterable implements Iterable { - private final Iterable as; - private final Set>> rateLimits; + private final Iterable as; + private final Set>> rateLimits; - public RateLimitingIterable(Iterable as, Set>> rateLimits) { - Set>> combinedRateLimits = new HashSet<>(rateLimits); + public RateLimitingIterable(Iterable as, Set>> rateLimits) { + Set>> combinedRateLimits = new HashSet<>(rateLimits); if (as instanceof RateLimitingIterable) { RateLimitingIterable inner = (RateLimitingIterable) as; combinedRateLimits.addAll(inner.rateLimits); diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/RateLimitingIterator.java similarity index 71% rename from src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterator.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/RateLimitingIterator.java index f7b622bb8..1046f406c 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/RateLimitingIterator.java @@ -1,6 +1,8 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; +import com.jnape.palatable.lambda.adt.Try; import com.jnape.palatable.lambda.adt.hlist.Tuple3; +import com.jnape.palatable.lambda.functions.Fn0; import java.time.Duration; import java.time.Instant; @@ -11,24 +13,25 @@ import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; -import java.util.function.Supplier; +import static com.jnape.palatable.lambda.adt.Try.failure; import static com.jnape.palatable.lambda.adt.Try.trying; import static com.jnape.palatable.lambda.functions.builtin.fn1.Size.size; import static com.jnape.palatable.lambda.functions.builtin.fn2.Filter.filter; import static com.jnape.palatable.lambda.functions.builtin.fn2.GTE.gte; import static com.jnape.palatable.lambda.functions.builtin.fn2.LT.lt; import static com.jnape.palatable.lambda.functions.builtin.fn2.LTE.lte; +import static com.jnape.palatable.lambda.monad.Monad.join; import static com.jnape.palatable.lambda.semigroup.builtin.Max.max; import static java.lang.Thread.sleep; import static java.util.Collections.emptyList; public final class RateLimitingIterator implements Iterator { - private final Iterator asIterator; - private final Set>> rateLimits; - private final Map>, List> timeSlicesByRateLimit; + private final Iterator asIterator; + private final Set>> rateLimits; + private final Map>, List> timeSlicesByRateLimit; - public RateLimitingIterator(Iterator asIterator, Set>> rateLimits) { + public RateLimitingIterator(Iterator asIterator, Set>> rateLimits) { this.asIterator = asIterator; this.rateLimits = rateLimits; timeSlicesByRateLimit = new HashMap<>(); @@ -51,23 +54,26 @@ private void awaitNextTimeSlice() { rateLimits.forEach(rateLimit -> { awaitNextTimeSliceForRateLimit(rateLimit); List timeSlicesForRateLimit = timeSlicesByRateLimit.getOrDefault(rateLimit, new ArrayList<>()); - timeSlicesForRateLimit.add(rateLimit._3().get()); + timeSlicesForRateLimit.add(rateLimit._3().apply()); timeSlicesByRateLimit.put(rateLimit, timeSlicesForRateLimit); }); } - private void awaitNextTimeSliceForRateLimit(Tuple3> rateLimit) { + private void awaitNextTimeSliceForRateLimit(Tuple3> rateLimit) { while (rateLimitExhaustedInTimeSlice(rateLimit)) { - trying(() -> sleep(0)).biMapL(IterationInterruptedException::new).orThrow(); + join(trying(() -> sleep(0)) + .fmap(Try::success) + .catching(InterruptedException.class, t -> failure(new IterationInterruptedException(t)))) + .orThrow(); } } - private boolean rateLimitExhaustedInTimeSlice(Tuple3> rateLimit) { + private boolean rateLimitExhaustedInTimeSlice(Tuple3> rateLimit) { List timeSlicesForRateLimit = timeSlicesByRateLimit.getOrDefault(rateLimit, emptyList()); return rateLimit.into((limit, duration, instantSupplier) -> { - Instant timeSliceEnd = instantSupplier.get(); + Instant timeSliceEnd = instantSupplier.apply(); Instant previousTimeSliceEnd = timeSliceEnd.minus(duration); - timeSlicesForRateLimit.removeIf(lt(previousTimeSliceEnd)); + timeSlicesForRateLimit.removeIf(lt(previousTimeSliceEnd).toPredicate()); return max(0L, limit - size(filter(mark -> lte(mark, previousTimeSliceEnd) && gte(mark, timeSliceEnd), timeSlicesForRateLimit))) == 0; }); } diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/RepetitiousIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/RepetitiousIterator.java similarity index 81% rename from src/main/java/com/jnape/palatable/lambda/iteration/RepetitiousIterator.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/RepetitiousIterator.java index 51a6715a5..55652d4c4 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/RepetitiousIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/RepetitiousIterator.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; public final class RepetitiousIterator extends InfiniteIterator { diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/ReversingIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ReversingIterable.java similarity index 92% rename from src/main/java/com/jnape/palatable/lambda/iteration/ReversingIterable.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/ReversingIterable.java index df4c25e45..29aff81db 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/ReversingIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ReversingIterable.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import java.util.Iterator; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/ReversingIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ReversingIterator.java similarity index 94% rename from src/main/java/com/jnape/palatable/lambda/iteration/ReversingIterator.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/ReversingIterator.java index 428898058..70e1baa60 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/ReversingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ReversingIterator.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import java.util.ArrayList; import java.util.Iterator; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/RewindableIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/RewindableIterator.java similarity index 96% rename from src/main/java/com/jnape/palatable/lambda/iteration/RewindableIterator.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/RewindableIterator.java index d4de2c5d7..5bdde4312 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/RewindableIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/RewindableIterator.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import java.util.Iterator; import java.util.NoSuchElementException; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/ScanningIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ScanningIterator.java similarity index 61% rename from src/main/java/com/jnape/palatable/lambda/iteration/ScanningIterator.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/ScanningIterator.java index d195b14b3..43fc4ece5 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/ScanningIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ScanningIterator.java @@ -1,16 +1,17 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; + +import com.jnape.palatable.lambda.functions.Fn2; import java.util.Iterator; import java.util.NoSuchElementException; -import java.util.function.BiFunction; public final class ScanningIterator extends ImmutableIterator { - private final BiFunction scanner; - private final Iterator asIterator; - private B b; + private final Fn2 scanner; + private final Iterator asIterator; + private B b; - public ScanningIterator(BiFunction scanner, B b, + public ScanningIterator(Fn2 scanner, B b, Iterator asIterator) { this.scanner = scanner; this.b = b; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/SnocIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/SnocIterable.java similarity index 93% rename from src/main/java/com/jnape/palatable/lambda/iteration/SnocIterable.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/SnocIterable.java index a16947b4a..9a0118200 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/SnocIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/SnocIterable.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import java.util.Collections; import java.util.Iterator; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/SnocIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/SnocIterator.java similarity index 91% rename from src/main/java/com/jnape/palatable/lambda/iteration/SnocIterator.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/SnocIterator.java index 7c084c7ab..e3c336a91 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/SnocIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/SnocIterator.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import java.util.Iterator; import java.util.NoSuchElementException; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/TakingIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/TakingIterable.java similarity index 91% rename from src/main/java/com/jnape/palatable/lambda/iteration/TakingIterable.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/TakingIterable.java index ce67f8e89..f228b596a 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/TakingIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/TakingIterable.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import java.util.Iterator; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/TakingIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/TakingIterator.java similarity index 92% rename from src/main/java/com/jnape/palatable/lambda/iteration/TakingIterator.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/TakingIterator.java index 3b558d68e..900f7ddb7 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/TakingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/TakingIterator.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import java.util.Iterator; import java.util.NoSuchElementException; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/UnfoldingIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/UnfoldingIterator.java similarity index 58% rename from src/main/java/com/jnape/palatable/lambda/iteration/UnfoldingIterator.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/UnfoldingIterator.java index 418121c7c..7ed719046 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/UnfoldingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/UnfoldingIterator.java @@ -1,19 +1,19 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn1; import java.util.NoSuchElementException; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; public final class UnfoldingIterator extends ImmutableIterator { - private final Function>> function; - private B seed; - private Maybe> maybeAcc; + private final Fn1>> function; + private B seed; + private Maybe> maybeAcc; - public UnfoldingIterator(Function>> function, B seed) { + public UnfoldingIterator(Fn1>> function, B seed) { this.function = function; this.seed = seed; } @@ -27,13 +27,12 @@ public boolean hasNext() { } @Override - @SuppressWarnings("ConstantConditions") public A next() { if (!hasNext()) throw new NoSuchElementException(); - Tuple2 acc = maybeAcc.orElseThrow(NoSuchElementException::new); - A next = acc._1(); + Tuple2 acc = maybeAcc.orElseThrow(NoSuchElementException::new); + A next = acc._1(); seed = acc._2(); maybeAcc = null; return next; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/UnioningIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/UnioningIterable.java similarity index 92% rename from src/main/java/com/jnape/palatable/lambda/iteration/UnioningIterable.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/UnioningIterable.java index 641ab8255..fc4c6ed60 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/UnioningIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/UnioningIterable.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import java.util.Iterator; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/ZippingIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ZippingIterator.java similarity index 54% rename from src/main/java/com/jnape/palatable/lambda/iteration/ZippingIterator.java rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/ZippingIterator.java index 1b0909fd4..107a6ec08 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/ZippingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ZippingIterator.java @@ -1,14 +1,15 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; + +import com.jnape.palatable.lambda.functions.Fn2; import java.util.Iterator; -import java.util.function.BiFunction; public final class ZippingIterator extends ImmutableIterator { - private final BiFunction zipper; - private final Iterator asIterator; - private final Iterator bsIterator; + private final Fn2 zipper; + private final Iterator asIterator; + private final Iterator bsIterator; - public ZippingIterator(BiFunction zipper, Iterator asIterator, + public ZippingIterator(Fn2 zipper, Iterator asIterator, Iterator bsIterator) { this.asIterator = asIterator; this.bsIterator = bsIterator; diff --git a/src/main/java/com/jnape/palatable/lambda/io/IO.java b/src/main/java/com/jnape/palatable/lambda/io/IO.java new file mode 100644 index 000000000..c86fcbc59 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/io/IO.java @@ -0,0 +1,339 @@ +package com.jnape.palatable.lambda.io; + +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.adt.Try; +import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.adt.choice.Choice2; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn0; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.SideEffect; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.monad.Monad; + +import java.util.LinkedList; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + +import static com.jnape.palatable.lambda.adt.Unit.UNIT; +import static com.jnape.palatable.lambda.adt.choice.Choice2.a; +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.Fn0.fn0; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; +import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft; +import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.recurse; +import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.terminate; +import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline; +import static com.jnape.palatable.lambda.monad.Monad.join; +import static java.util.concurrent.CompletableFuture.completedFuture; +import static java.util.concurrent.CompletableFuture.supplyAsync; +import static java.util.concurrent.ForkJoinPool.commonPool; + +/** + * A {@link Monad} representing some side-effecting computation to be performed. Note that because {@link IO} inherently + * offers an interface supporting parallelism, the optimal execution strategy for any given {@link IO} is encoded in + * its composition. + * + * @param the result type + */ +public abstract class IO implements Monad> { + + private IO() { + } + + /** + * Run the effect represented by this {@link IO} instance, blocking the current thread until the effect terminates. + * + * @return the result of the effect + */ + public abstract A unsafePerformIO(); + + /** + * Returns a {@link CompletableFuture} representing the result of this eventual effect. By default, this will + * immediately run the effect in terms of the implicit {@link Executor} available to {@link CompletableFuture} + * (usually the {@link java.util.concurrent.ForkJoinPool}). Note that specific {@link IO} constructions may allow + * this method to delegate to externally-managed {@link CompletableFuture} instead of synthesizing their own. + * + * @return the {@link CompletableFuture} representing this {@link IO}'s eventual result + * @see IO#unsafePerformAsyncIO(Executor) + */ + public final CompletableFuture unsafePerformAsyncIO() { + return unsafePerformAsyncIO(commonPool()); + } + + /** + * Returns a {@link CompletableFuture} representing the result of this eventual effect. By default, this will + * immediately run the effect in terms of the provided {@link Executor}. Note that specific {@link IO} + * constructions may allow this method to delegate to externally-managed {@link CompletableFuture} instead of + * synthesizing their own. + * + * @param executor the {@link Executor} to run the {@link CompletableFuture} from + * @return the {@link CompletableFuture} representing this {@link IO}'s eventual result + * @see IO#unsafePerformAsyncIO() + */ + public abstract CompletableFuture unsafePerformAsyncIO(Executor executor); + + /** + * Given a function from any {@link Throwable} to the result type A, if this {@link IO} successfully + * yields a result, return it; otherwise, map the {@link Throwable} to the result type and return that. + * + * @param recoveryFn the recovery function + * @return the guarded {@link IO} + */ + public final IO exceptionally(Fn1 recoveryFn) { + return new IO() { + @Override + public A unsafePerformIO() { + return Try.trying(IO.this::unsafePerformIO).recover(recoveryFn); + } + + @Override + public CompletableFuture unsafePerformAsyncIO(Executor executor) { + return IO.this.unsafePerformAsyncIO(executor).exceptionally(recoveryFn::apply); + } + }; + } + + /** + * Return an {@link IO} that will run ensureIO strictly after running this {@link IO} regardless of + * whether this {@link IO} terminates normally, analogous to a finally block. + * + * @param ensureIO the {@link IO} to ensure runs strictly after this {@link IO} + * @return the combined {@link IO} + */ + public final IO ensuring(IO ensureIO) { + return join(fmap(a -> ensureIO.fmap(constantly(a))) + .exceptionally(t -> join(ensureIO.>fmap(constantly(io(() -> {throw t;}))) + .exceptionally(t2 -> io(() -> { + t.addSuppressed(t2); + throw t; + }))))); + } + + /** + * Return a safe {@link IO} that will never throw by lifting the result of this {@link IO} into {@link Either}, + * catching any {@link Throwable} and wrapping it in a {@link Either#left(Object) left}. + * + * @return the safe {@link IO} + */ + public final IO> safe() { + return fmap(Either::right).exceptionally(Either::left); + } + + /** + * {@inheritDoc} + */ + @Override + public final IO pure(B b) { + return io(b); + } + + /** + * {@inheritDoc} + */ + @Override + public final IO fmap(Fn1 fn) { + return Monad.super.fmap(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public final IO zip(Applicative, IO> appFn) { + @SuppressWarnings("unchecked") + IO source = (IO) this; + @SuppressWarnings("unchecked") + IO> zip = (IO>) (Object) appFn; + return new Compose<>(source, a(zip)); + } + + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip(Lazy, IO>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); + } + + /** + * {@inheritDoc} + */ + @Override + public final IO discardL(Applicative> appB) { + return Monad.super.discardL(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public final IO discardR(Applicative> appB) { + return Monad.super.discardR(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public final IO flatMap(Fn1>> f) { + @SuppressWarnings("unchecked") + IO source = (IO) this; + @SuppressWarnings({"unchecked", "RedundantCast"}) + Fn1> flatMap = (Fn1>) (Object) f; + return new Compose<>(source, Choice2.b(flatMap)); + } + + /** + * Produce an {@link IO} that throws the given {@link Throwable} when executed. + * + * @param t the {@link Throwable} + * @param any result type + * @return the {@link IO} + */ + public static IO throwing(Throwable t) { + return io(() -> {throw t;}); + } + + /** + * Static factory method for creating an {@link IO} that just returns a when performed. + * + * @param a the result + * @param the result type + * @return the {@link IO} + */ + public static IO io(A a) { + return new IO() { + @Override + public A unsafePerformIO() { + return a; + } + + @Override + public CompletableFuture unsafePerformAsyncIO(Executor executor) { + return completedFuture(a); + } + }; + } + + /** + * Static factory method for coercing a lambda to an {@link IO}. + * + * @param fn0 the lambda to coerce + * @param the result type + * @return the {@link IO} + */ + public static IO io(Fn0 fn0) { + return new IO() { + @Override + public A unsafePerformIO() { + return fn0.apply(); + } + + @Override + public CompletableFuture unsafePerformAsyncIO(Executor executor) { + return supplyAsync(fn0::apply, executor); + } + }; + } + + /** + * Static factory method for creating an {@link IO} that runs a {@link SideEffect} and returns {@link Unit}. + * + * @param sideEffect the {@link SideEffect} + * @return the {@link IO} + */ + public static IO io(SideEffect sideEffect) { + return io(fn0(() -> { + sideEffect.Ω(); + return UNIT; + })); + } + + /** + * Static factory method for creating an {@link IO} from an externally managed source of + * {@link CompletableFuture completable futures}. + *

+ * Note that constructing an {@link IO} this way results in no intermediate futures being constructed by either + * {@link IO#unsafePerformAsyncIO()} or {@link IO#unsafePerformAsyncIO(Executor)}, and {@link IO#unsafePerformIO()} + * is synonymous with invoking {@link CompletableFuture#get()} on the externally managed future. + * + * @param supplier the source of externally managed {@link CompletableFuture completable futures} + * @param the result type + * @return the {@link IO} + */ + public static IO externallyManaged(Fn0> supplier) { + return new IO() { + @Override + public A unsafePerformIO() { + return fn0(() -> unsafePerformAsyncIO().get()).apply(); + } + + @Override + public CompletableFuture unsafePerformAsyncIO(Executor executor) { + return supplier.apply(); + } + }; + } + + private static final class Compose extends IO { + private final IO source; + private final Choice2>, Fn1>> composition; + + private Compose(IO source, Choice2>, Fn1>> composition) { + this.source = source; + this.composition = composition; + } + + @Override + public A unsafePerformIO() { + @SuppressWarnings("unchecked") + A result = (A) trampoline(into((source, compositions) -> { + Object res = source.unsafePerformIO(); + return compositions.isEmpty() + ? terminate(res) + : compositions.pop().match( + zip -> recurse(tuple(io(zip.unsafePerformIO().apply(res)), compositions)), + flatMap -> { + IO next = flatMap.apply(res); + return (next instanceof Compose) + ? recurse(((Compose) next).deforest(compositions)) + : recurse(tuple(next, compositions)); + }); + }), deforest(new LinkedList<>())); + + return result; + } + + @Override + public CompletableFuture unsafePerformAsyncIO(Executor executor) { + @SuppressWarnings("unchecked") + CompletableFuture future = (CompletableFuture) deforest(new LinkedList<>()) + .into((source, compositions) -> foldLeft( + (ioFuture, composition) -> composition + .match(zip -> zip.unsafePerformAsyncIO(executor) + .thenComposeAsync(f -> ioFuture.thenApply(f.toFunction()), executor), + flatMap -> ioFuture.thenComposeAsync(obj -> flatMap.apply(obj) + .unsafePerformAsyncIO(executor), executor)), + source.unsafePerformAsyncIO(executor), + compositions)); + return future; + } + + private Tuple2, LinkedList>, Fn1>>>> + deforest(LinkedList>, Fn1>>> branches) { + Tuple2, LinkedList>, Fn1>>>> args = + tuple(this, branches); + return trampoline(into((source, compositions) -> { + IO leaf = source.source; + compositions.push(source.composition); + return leaf instanceof Compose + ? recurse(tuple((Compose) leaf, compositions)) + : terminate(tuple(leaf, compositions)); + }), args); + } + + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/MappingIterable.java b/src/main/java/com/jnape/palatable/lambda/iteration/MappingIterable.java deleted file mode 100644 index 1730a6838..000000000 --- a/src/main/java/com/jnape/palatable/lambda/iteration/MappingIterable.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.jnape.palatable.lambda.iteration; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.function.Function; - -import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft; -import static java.util.Collections.singletonList; - -public final class MappingIterable implements Iterable { - private final Iterable as; - private final List mappers; - - @SuppressWarnings("unchecked") - public MappingIterable(Function fn, Iterable as) { - List mappers = new ArrayList<>(singletonList(fn)); - while (as instanceof MappingIterable) { - MappingIterable nested = (MappingIterable) as; - as = (Iterable) nested.as; - mappers.addAll(0, nested.mappers); - } - this.as = as; - this.mappers = mappers; - } - - @Override - @SuppressWarnings("unchecked") - public Iterator iterator() { - Function fnComposedOnTheHeap = o -> foldLeft((x, fn) -> fn.apply(x), o, mappers); - return new MappingIterator<>(fnComposedOnTheHeap, as.iterator()); - } -} diff --git a/src/main/java/com/jnape/palatable/lambda/lens/Iso.java b/src/main/java/com/jnape/palatable/lambda/lens/Iso.java deleted file mode 100644 index bff042842..000000000 --- a/src/main/java/com/jnape/palatable/lambda/lens/Iso.java +++ /dev/null @@ -1,319 +0,0 @@ -package com.jnape.palatable.lambda.lens; - -import com.jnape.palatable.lambda.adt.hlist.Tuple2; -import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.Fn2; -import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.functor.Functor; -import com.jnape.palatable.lambda.functor.Profunctor; -import com.jnape.palatable.lambda.functor.builtin.Exchange; -import com.jnape.palatable.lambda.functor.builtin.Identity; -import com.jnape.palatable.lambda.lens.functions.Over; -import com.jnape.palatable.lambda.lens.functions.Set; -import com.jnape.palatable.lambda.lens.functions.View; -import com.jnape.palatable.lambda.monad.Monad; - -import java.util.function.Function; - -import static com.jnape.palatable.lambda.functions.Fn1.fn1; -import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; -import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; -import static com.jnape.palatable.lambda.lens.Iso.Simple.adapt; -import static com.jnape.palatable.lambda.lens.functions.View.view; - -/** - * An {@link Iso} (short for "isomorphism") is an invertible {@link Lens}: a {@link LensLike} encoding of a - * bi-directional focusing of two types, and like {@link Lens}es, can be {@link View}ed, - * {@link Set}, and {@link Over}ed. - *

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

- * {@code
- * Iso stringIntIso = Iso.iso(Integer::parseInt, Object::toString);
- * Integer asInt = view(stringIntIso, "123"); // 123
- * String asString = view(stringIntIso.mirror(), 123); // "123"
- * }
- * 
- * In the previous example, stringIntIso can be viewed as a {@link Lens}<String, String, Integer, - * Integer>, and can be {@link Iso#mirror}ed and viewed as a {@link Lens}<Integer, - * Integer, String, String>. - *

- * As with {@link Lens}, variance is supported between S/T and A/B, and where these pairs do - * not vary, a {@link Simple} iso can be used (for instance, in the previous example, stringIntIso could - * have had the simplified Iso.Simple<String, Integer> type). - *

- * For more information, read about isos. - * - * @param the larger type for focusing - * @param the larger type for mirrored focusing - * @param the smaller type for focusing - * @param the smaller type for mirrored focusing - */ -@FunctionalInterface -public interface Iso extends LensLike { - -

, FT extends Functor, - PAFB extends Profunctor, - PSFT extends Profunctor> PSFT apply(PAFB pafb); - - @Override - default , FB extends Functor> FT apply( - Function fn, S s) { - return this., Fn1>apply(fn1(fn)).apply(s); - } - - /** - * Convert this {@link Iso} into a {@link Lens}. - * - * @return the equivalent lens - */ - default Lens toLens() { - return new Lens() { - @Override - public , FB extends Functor> FT apply( - Function fn, S s) { - return Iso.this.apply(fn, s); - } - }; - } - - /** - * Flip this {@link Iso} around. - * - * @return the mirrored {@link Iso} - */ - default Iso mirror() { - return unIso().into((sa, bt) -> iso(bt, sa)); - } - - /** - * Destructure this {@link Iso} into the two functions S -< A and B -< T that - * constitute the isomorphism. - * - * @return the destructured iso - */ - default Tuple2, Fn1> unIso() { - return Tuple2.fill(this., Identity, Identity, Identity, - Exchange>, - Exchange>>apply(new Exchange<>(id(), Identity::new)).diMapR(Identity::runIdentity)) - .biMap(e -> fn1(e.sa()), e -> fn1(e.bt())); - } - - @Override - default Iso fmap(Function fn) { - return LensLike.super.fmap(fn).coerce(); - } - - @Override - default Iso pure(U u) { - return iso(view(this), constantly(u)); - } - - @Override - default Iso zip(Applicative, LensLike> appFn) { - return LensLike.super.zip(appFn).coerce(); - } - - @Override - default Iso discardL(Applicative> appB) { - return LensLike.super.discardL(appB).coerce(); - } - - @Override - default Iso discardR(Applicative> appB) { - return LensLike.super.discardR(appB).coerce(); - } - - @Override - default Iso flatMap(Function>> fn) { - return unIso().fmap(bt -> Fn2.fn2(fn1(bt.andThen(fn.>andThen(Applicative::coerce)) - .andThen(Iso::unIso) - .andThen(Tuple2::_2) - .andThen(Fn1::fn1)))) - .fmap(Fn2::uncurry) - .fmap(bbu -> bbu.diMapL(Tuple2::fill)) - .into(Iso::iso); - } - - @Override - default Iso diMapL(Function fn) { - return LensLike.super.diMapL(fn).coerce(); - } - - @Override - default Iso diMapR(Function fn) { - return LensLike.super.diMapR(fn).coerce(); - } - - @Override - default Iso diMap(Function lFn, - Function rFn) { - return LensLike.super.diMap(lFn, rFn).coerce(); - } - - @Override - default Iso contraMap(Function fn) { - return LensLike.super.contraMap(fn).coerce(); - } - - @Override - default Iso mapS(Function fn) { - return unIso().biMapL(f -> f.compose(fn)).into(Iso::iso); - } - - @Override - default Iso mapT(Function fn) { - return unIso().biMapR(f -> f.andThen(fn)).into(Iso::iso); - } - - @Override - default Iso mapA(Function fn) { - return unIso().biMapL(f -> f.andThen(fn)).into(Iso::iso); - } - - @Override - default Iso mapB(Function fn) { - return unIso().biMapR(f -> f.compose(fn)).into(Iso::iso); - } - - @Override - default Lens andThen(LensLike f) { - return toLens().andThen(f); - } - - /** - * Left-to-right composition of {@link Iso}. - * - * @param f the iso to apply after this one - * @param the smaller type the first larger type can be viewed as - * @param the smaller type that can be viewed as the second larger type - * @return the composed {@link Iso} - */ - default Iso andThen(Iso f) { - return unIso().into((sa, bt) -> f.unIso().into((ac, db) -> iso(sa.andThen(ac), db.andThen(bt)))); - } - - /** - * Right-to-left composition of {@link Iso}. - * - * @param g the iso to apply before this one - * @param the larger type that can be viewed as the first smaller type - * @param the larger type the second smaller type can be viewed as - * @return the composed {@link Iso} - */ - default Iso compose(Iso g) { - return g.andThen(this); - } - - @Override - default Lens compose(LensLike f) { - return toLens().compose(f); - } - - /** - * Static factory method for creating an iso from a function and it's inverse. - * - * @param f the function - * @param g f's inverse - * @param the larger type for focusing - * @param the larger type for mirrored focusing - * @param the smaller type for focusing - * @param the smaller type for mirrored focusing - * @return the iso - */ - static Iso iso(Function f, - Function g) { - return new Iso() { - @Override - @SuppressWarnings("unchecked") - public

, FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply( - PAFB pafb) { - return (PSFT) pafb.diMap(f, fb -> (FT) fb.fmap(g)); - } - }; - } - - /** - * Static factory method for creating a simple {@link Iso} from a function and its inverse. - * - * @param f a function - * @param g f's inverse - * @param one side of the isomorphism - * @param the other side of the isomorphism - * @return the simple iso - */ - static Iso.Simple simpleIso(Function f, Function g) { - return adapt(iso(f, g)); - } - - /** - * A convenience type with a simplified type signature for common isos with both unified "larger" values and - * unified "smaller" values. - * - * @param the type of both "larger" values - * @param the type of both "smaller" values - */ - @FunctionalInterface - interface Simple extends Iso, LensLike.Simple { - - /** - * Compose two simple isos from right to left. - * - * @param g the other simple iso - * @param the other simple iso' larger type - * @return the composed simple iso - */ - default Iso.Simple compose(Iso.Simple g) { - return Iso.Simple.adapt(Iso.super.compose(g)); - } - - /** - * Compose two simple isos from left to right. - * - * @param f the other simple iso - * @param the other simple iso' smaller type - * @return the composed simple iso - */ - default Iso.Simple andThen(Iso.Simple f) { - return adapt(f.compose(this)); - } - - @Override - default Iso.Simple mirror() { - return adapt(Iso.super.mirror()); - } - - @Override - default Lens.Simple toLens() { - return Lens.Simple.adapt(Iso.super.toLens()); - } - - @Override - default Iso.Simple discardR(Applicative> appB) { - return adapt(Iso.super.discardR(appB)); - } - - @Override - default Lens.Simple compose(LensLike.Simple g) { - return toLens().compose(g); - } - - @Override - default Lens.Simple andThen(LensLike.Simple f) { - return toLens().andThen(f); - } - - /** - * Adapt an {@link Iso} with the right variance to an {@link Iso.Simple}. - * - * @param iso the iso - * @param S/T - * @param A/B - * @return the simple iso - */ - @SuppressWarnings("unchecked") - static Iso.Simple adapt(Iso iso) { - return iso::apply; - } - } -} \ No newline at end of file diff --git a/src/main/java/com/jnape/palatable/lambda/lens/LensLike.java b/src/main/java/com/jnape/palatable/lambda/lens/LensLike.java deleted file mode 100644 index 5551e172a..000000000 --- a/src/main/java/com/jnape/palatable/lambda/lens/LensLike.java +++ /dev/null @@ -1,159 +0,0 @@ -package com.jnape.palatable.lambda.lens; - -import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.functor.Functor; -import com.jnape.palatable.lambda.functor.Profunctor; -import com.jnape.palatable.lambda.monad.Monad; - -import java.util.function.Function; - -/** - * The generic supertype of all types that can be treated as lenses but should preserve type-specific return types in - * overrides. This type only exists to appease Java's unfortunate parametric type hierarchy constraints. If you're here, - * you're probably looking for {@link Lens} or {@link Iso}. - * - * @param the type of the "larger" value for reading - * @param the type of the "larger" value for putting - * @param the type of the "smaller" value that is read - * @param the type of the "smaller" update value - * @param the concrete lens subtype - * @see Lens - * @see Iso - */ -public interface LensLike extends Monad>, Profunctor> { - - , FB extends Functor> FT apply( - Function fn, S s); - - /** - * Right-to-left composition of lenses. Requires compatibility between A and B. - * - * @param g the other lens - * @param the new "larger" value for reading (previously S) - * @param the new "larger" value for putting (previously T) - * @return the composed lens - */ - LensLike compose(LensLike g); - - /** - * Left-to-right composition of lenses. Requires compatibility between S and T. - * - * @param f the other lens - * @param the new "smaller" value to read (previously A) - * @param the new "smaller" update value (previously B) - * @return the composed lens - */ - LensLike andThen(LensLike f); - - /** - * Contravariantly map S to R, yielding a new lens. - * - * @param fn the mapping function - * @param the type of the new "larger" value for reading - * @return the new lens - */ - LensLike mapS(Function fn); - - /** - * Covariantly map T to U, yielding a new lens. - * - * @param fn the mapping function - * @param the type of the new "larger" value for putting - * @return the new lens - */ - LensLike mapT(Function fn); - - /** - * Covariantly map A to C, yielding a new lens. - * - * @param fn the mapping function - * @param the type of the new "smaller" value that is read - * @return the new lens - */ - LensLike mapA(Function fn); - - /** - * Contravariantly map B to Z, yielding a new lens. - * - * @param fn the mapping function - * @param the type of the new "smaller" update value - * @return the new lens - */ - LensLike mapB(Function fn); - - @Override - LensLike flatMap(Function>> f); - - @Override - LensLike pure(U u); - - @Override - default LensLike fmap(Function fn) { - return Monad.super.fmap(fn).coerce(); - } - - @Override - default LensLike zip( - Applicative, LensLike> appFn) { - return Monad.super.zip(appFn).coerce(); - } - - @Override - default LensLike discardL(Applicative> appB) { - return Monad.super.discardL(appB).coerce(); - } - - @Override - default LensLike discardR(Applicative> appB) { - return Monad.super.discardR(appB).coerce(); - } - - @Override - default LensLike diMapL(Function fn) { - return (LensLike) Profunctor.super.diMapL(fn); - } - - @Override - default LensLike diMapR(Function fn) { - return (LensLike) Profunctor.super.diMapR(fn); - } - - @Override - default LensLike diMap(Function lFn, - Function rFn) { - return this.mapS(lFn).mapT(rFn); - } - - @Override - default LensLike contraMap(Function fn) { - return (LensLike) Profunctor.super.contraMap(fn); - } - - /** - * A simpler type signature for lenses where S/T and A/B are equivalent. - * - * @param the "larger" type - * @param the "smaller" type - * @param the concrete lens subtype - */ - interface Simple extends LensLike { - - /** - * Compose two simple lenses from right to left. - * - * @param g the other simple lens - * @param the other simple lens' larger type - * @return the composed simple lens - */ - LensLike.Simple compose(LensLike.Simple g); - - /** - * Compose two simple lenses from left to right. - * - * @param f the other simple lens - * @param the other simple lens' smaller type - * @return the composed simple lens - */ - LensLike.Simple andThen(LensLike.Simple f); - } -} diff --git a/src/main/java/com/jnape/palatable/lambda/lens/functions/Over.java b/src/main/java/com/jnape/palatable/lambda/lens/functions/Over.java deleted file mode 100644 index 5c1de0104..000000000 --- a/src/main/java/com/jnape/palatable/lambda/lens/functions/Over.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.jnape.palatable.lambda.lens.functions; - -import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.Fn2; -import com.jnape.palatable.lambda.functions.Fn3; -import com.jnape.palatable.lambda.functor.builtin.Identity; -import com.jnape.palatable.lambda.lens.LensLike; - -import java.util.function.Function; - -/** - * Given a lens, a function from A to B, and a "larger" value S, produce a - * T by retrieving the A from the S, applying the function, and updating the - * S with the B resulting from the function. - *

- * This function is similar to {@link Set}, except that it allows the setting value B to be derived from - * S via function application, rather than provided. - * - * @param the type of the larger value - * @param the type of the larger updated value - * @param the type of the smaller retrieving value - * @param the type of the smaller setting value - * @see Set - * @see View - */ -public final class Over implements Fn3, Function, S, T> { - - private static final Over INSTANCE = new Over(); - - private Over() { - } - - @Override - public T apply(LensLike lens, Function fn, S s) { - return lens., Identity>apply(fn.andThen((Function>) Identity::new), s).runIdentity(); - } - - @SuppressWarnings("unchecked") - public static Over over() { - return (Over) INSTANCE; - } - - public static Fn2, S, T> over(LensLike lens) { - return Over.over().apply(lens); - } - - public static Fn1 over(LensLike lens, Function fn) { - return over(lens).apply(fn); - } - - public static T over(LensLike lens, Function fn, S s) { - return over(lens, fn).apply(s); - } -} diff --git a/src/main/java/com/jnape/palatable/lambda/lens/functions/Set.java b/src/main/java/com/jnape/palatable/lambda/lens/functions/Set.java deleted file mode 100644 index 07c97b804..000000000 --- a/src/main/java/com/jnape/palatable/lambda/lens/functions/Set.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.jnape.palatable.lambda.lens.functions; - -import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.Fn2; -import com.jnape.palatable.lambda.functions.Fn3; -import com.jnape.palatable.lambda.functor.builtin.Identity; -import com.jnape.palatable.lambda.lens.LensLike; - -import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; -import static com.jnape.palatable.lambda.lens.functions.Over.over; - -/** - * Given a lens, a "smaller" value B, and a "larger" value S, produce a T by - * lifting the lens into {@link Identity}. - *

- * More idiomatically, this function can be used to treat a lens as a "setter" of Bs on Ss, - * potentially producing a different "larger" value, T. - * - * @param the type of the larger value - * @param the type of the larger updated value - * @param the type of the smaller retrieving value (unused, but necessary for composition) - * @param the type of the smaller setting value - * @see Over - * @see View - */ -public final class Set implements Fn3, B, S, T> { - - private static final Set INSTANCE = new Set(); - - private Set() { - } - - @Override - public T apply(LensLike lens, B b, S s) { - return over(lens, constantly(b), s); - } - - @SuppressWarnings("unchecked") - public static Set set() { - return INSTANCE; - } - - public static Fn2 set(LensLike lens) { - return Set.set().apply(lens); - } - - public static Fn1 set(LensLike lens, B b) { - return set(lens).apply(b); - } - - public static T set(LensLike lens, B b, S s) { - return set(lens, b).apply(s); - } -} diff --git a/src/main/java/com/jnape/palatable/lambda/lens/functions/Under.java b/src/main/java/com/jnape/palatable/lambda/lens/functions/Under.java deleted file mode 100644 index 11c37a1e5..000000000 --- a/src/main/java/com/jnape/palatable/lambda/lens/functions/Under.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.jnape.palatable.lambda.lens.functions; - -import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.Fn2; -import com.jnape.palatable.lambda.functions.Fn3; -import com.jnape.palatable.lambda.lens.Iso; -import com.jnape.palatable.lambda.lens.LensLike; - -import java.util.function.Function; - -/** - * The inverse of {@link Over}: given an {@link Iso}, a function from T to S, and a "smaller" - * value B, return a "smaller" value A by traversing around the type ring (B -> T - * -> S -> A). - *

- * Note this is only possible for {@link Iso}s and not general {@link LensLike}s because of the mandatory need for the - * correspondence B -> T. - * - * @param the larger type for focusing - * @param the larger type for mirrored focusing - * @param the smaller type for focusing - * @param the smaller type for mirrored focusing - */ -public final class Under implements Fn3, Function, B, A> { - - private static final Under INSTANCE = new Under(); - - private Under() { - } - - @Override - public A apply(Iso iso, Function fn, B b) { - return iso.unIso().into((sa, bt) -> bt.fmap(fn).fmap(sa)).apply(b); - } - - @SuppressWarnings("unchecked") - public static Under under() { - return INSTANCE; - } - - public static Fn2, B, A> under(Iso iso) { - return Under.under().apply(iso); - } - - public static Fn1 under(Iso iso, Function fn) { - return under(iso).apply(fn); - } - - public static A under(Iso iso, Function fn, B b) { - return under(iso, fn).apply(b); - } -} diff --git a/src/main/java/com/jnape/palatable/lambda/lens/functions/View.java b/src/main/java/com/jnape/palatable/lambda/lens/functions/View.java deleted file mode 100644 index a6d1cb883..000000000 --- a/src/main/java/com/jnape/palatable/lambda/lens/functions/View.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.jnape.palatable.lambda.lens.functions; - -import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.Fn2; -import com.jnape.palatable.lambda.functor.builtin.Const; -import com.jnape.palatable.lambda.lens.LensLike; - -/** - * Given a lens and a "larger" value S, retrieve a "smaller" value A by lifting the lens into - * {@link Const}. - *

- * More idiomatically, this function can be used to treat a lens as a "getter" of As from Ss. - * - * @param the type of the larger value - * @param the type of the larger updated value (unused, but necessary for composition) - * @param the type of the smaller retrieving value - * @param the type of the smaller setting value (unused, but necessary for composition) - * @see Set - * @see Over - */ -public final class View implements Fn2, S, A> { - - private static final View INSTANCE = new View(); - - private View() { - } - - @Override - public A apply(LensLike lens, S s) { - return lens., Const, Const>apply(Const::new, s).runConst(); - } - - @SuppressWarnings("unchecked") - public static View view() { - return INSTANCE; - } - - public static Fn1 view(LensLike lens) { - return View.view().apply(lens); - } - - public static A view(LensLike lens, S s) { - return view(lens).apply(s); - } -} diff --git a/src/main/java/com/jnape/palatable/lambda/monad/Monad.java b/src/main/java/com/jnape/palatable/lambda/monad/Monad.java index 4c3e2e18d..769218304 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/Monad.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/Monad.java @@ -1,16 +1,16 @@ package com.jnape.palatable.lambda.monad; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn1.Id; import com.jnape.palatable.lambda.functor.Applicative; - -import java.util.function.Function; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; /** * Monads are {@link Applicative} functors that support a flattening operation to unwrap M<M<A>> * -> M<A>. This flattening operation, coupled with {@link Applicative#zip(Applicative)}, gives rise to - * {@link Monad#flatMap(Function)}, a binding operation that maps the carrier value to a new monad instance in the same + * {@link Monad#flatMap(Fn1)}, a binding operation that maps the carrier value to a new monad instance in the same * category, and then unwraps the outer layer. *

* In addition to the applicative laws, there are 3 specific monad laws that monads should obey: @@ -26,7 +26,7 @@ * @param the type of the parameter * @param the unification parameter to more tightly type-constrain Monads to themselves */ -public interface Monad extends Applicative { +public interface Monad> extends Applicative { /** * Chain dependent computations that may continue or short-circuit based on previous results. @@ -35,7 +35,7 @@ public interface Monad extends Applicative { * @param the resulting monad parameter type * @return the new monad instance */ - Monad flatMap(Function> f); + Monad flatMap(Fn1> f); /** * {@inheritDoc} @@ -47,16 +47,25 @@ public interface Monad extends Applicative { * {@inheritDoc} */ @Override - default Monad fmap(Function fn) { - return flatMap(fn.andThen(this::pure)); + default Monad fmap(Fn1 fn) { + return flatMap(fn.fmap(this::pure)); + } + + /** + * {@inheritDoc} + */ + @Override + default Monad zip(Applicative, M> appFn) { + return appFn., M>>coerce().flatMap(this::fmap); } /** * {@inheritDoc} */ @Override - default Monad zip(Applicative, M> appFn) { - return appFn., M>>coerce().flatMap(this::fmap); + default Lazy> lazyZip( + Lazy, M>> lazyAppFn) { + return Applicative.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); } /** @@ -76,7 +85,7 @@ default Monad discardR(Applicative appB) { } /** - * Convenience static method equivalent to {@link Monad#flatMap(Function) flatMap}{@link Id#id() (id())}; + * Convenience static method equivalent to {@link Monad#flatMap(Fn1) flatMap}{@link Id#id() (id())}; * * @param mma the outer monad * @param the monad type @@ -84,7 +93,7 @@ default Monad discardR(Applicative appB) { * @param the nested monad * @return the nested monad */ - static > MA join(Monad mma) { + static , A, MA extends Monad> MA join(Monad mma) { return mma.flatMap(id()).coerce(); } } \ No newline at end of file diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java new file mode 100644 index 000000000..17b6dfd4e --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java @@ -0,0 +1,101 @@ +package com.jnape.palatable.lambda.monad.transformer; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.transformer.builtin.MaybeT; + +/** + * An interface representing a {@link Monad} transformer. + *

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

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

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

+ * For more information, read more about + * monad transformers. + * + * @param the outer {@link Monad monad} + * @param the inner {@link Monad monad} + * @param the carrier type + * @see MaybeT + */ +public interface MonadT, G extends Monad, A> + extends Monad> { + + /** + * Extract out the composed monad out of this transformer. + * + * @param the inferred embedded monad + * @param the inferred composed monad + * @return the composed monad + */ + , FGA extends Monad> FGA run(); + + /** + * {@inheritDoc} + */ + @Override + MonadT flatMap(Fn1>> f); + + /** + * {@inheritDoc} + */ + @Override + MonadT pure(B b); + + /** + * {@inheritDoc} + */ + @Override + default MonadT fmap(Fn1 fn) { + return Monad.super.fmap(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default MonadT zip(Applicative, MonadT> appFn) { + return Monad.super.zip(appFn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default Lazy> lazyZip( + Lazy, MonadT>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); + } + + /** + * {@inheritDoc} + */ + @Override + default MonadT discardL(Applicative> appB) { + return Monad.super.discardL(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default MonadT discardR(Applicative> appB) { + return Monad.super.discardR(appB).coerce(); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java new file mode 100644 index 000000000..d8a139f39 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java @@ -0,0 +1,131 @@ +package com.jnape.palatable.lambda.monad.transformer.builtin; + +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.builtin.Compose; +import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.transformer.MonadT; + +import java.util.Objects; + +import static com.jnape.palatable.lambda.adt.Either.left; +import static com.jnape.palatable.lambda.adt.Either.right; + +/** + * A {@link MonadT monad transformer} for {@link Either}. + * + * @param the outer {@link Monad} + * @param the left type + * @param the right type + */ +public final class EitherT, L, R> implements MonadT, R> { + + private final Monad, M> melr; + + private EitherT(Monad, M> melr) { + this.melr = melr; + } + + /** + * {@inheritDoc} + */ + @Override + public >, FGA extends Monad> FGA run() { + return melr.fmap(Either::coerce).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public EitherT flatMap(Fn1, ?>>> f) { + return eitherT(melr.flatMap(lr -> lr.match(l -> melr.pure(left(l)), + r -> f.apply(r).>coerce().run()))); + } + + /** + * {@inheritDoc} + */ + @Override + public EitherT pure(R2 r2) { + return eitherT(melr.pure(right(r2))); + } + + /** + * {@inheritDoc} + */ + @Override + public EitherT fmap(Fn1 fn) { + return MonadT.super.fmap(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public EitherT zip( + Applicative, MonadT, ?>> appFn) { + return MonadT.super.zip(appFn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, MonadT, ?>>> lazyAppFn) { + return new Compose<>(melr) + .lazyZip(lazyAppFn.fmap(maybeT -> new Compose<>( + maybeT.>>coerce() + .>, + Monad>, M>>run()))) + .fmap(compose -> eitherT(compose.getCompose())); + } + + /** + * {@inheritDoc} + */ + @Override + public EitherT discardL(Applicative, ?>> appB) { + return MonadT.super.discardL(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public EitherT discardR(Applicative, ?>> appB) { + return MonadT.super.discardR(appB).coerce(); + } + + @Override + public boolean equals(Object other) { + return other instanceof EitherT && Objects.equals(melr, ((EitherT) other).melr); + } + + @Override + public int hashCode() { + return Objects.hash(melr); + } + + @Override + public String toString() { + return "EitherT{melr=" + melr + '}'; + } + + /** + * Static factory method for lifting a {@link Monad}<{@link Either}<L, R>, M> into an + * {@link EitherT}. + * + * @param melr the {@link Monad}<{@link Either}<L, R>, M> + * @param the outer {@link Monad} unification parameter + * @param the left type + * @param the right type + * @return the {@link EitherT} + */ + public static , L, R> EitherT eitherT(Monad, M> melr) { + return new EitherT<>(melr); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java new file mode 100644 index 000000000..a3e87e3fc --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java @@ -0,0 +1,124 @@ +package com.jnape.palatable.lambda.monad.transformer.builtin; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.builtin.Compose; +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.transformer.MonadT; + +import java.util.Objects; + +/** + * A {@link MonadT monad transformer} for {@link Identity}. + * + * @param the outer {@link Monad} + * @param the carrier type + */ +public final class IdentityT, A> implements MonadT, A> { + + private final Monad, M> mia; + + private IdentityT(Monad, M> mia) { + this.mia = mia; + } + + /** + * {@inheritDoc} + */ + @Override + public >, FGA extends Monad> FGA run() { + return mia.fmap(Identity::coerce).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public IdentityT flatMap(Fn1, ?>>> f) { + return identityT(mia.flatMap(identityA -> f.apply(identityA.runIdentity()).>coerce().run())); + } + + /** + * {@inheritDoc} + */ + @Override + public IdentityT pure(B b) { + return identityT(mia.pure(new Identity<>(b))); + } + + /** + * {@inheritDoc} + */ + @Override + public IdentityT fmap(Fn1 fn) { + return MonadT.super.fmap(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public IdentityT zip(Applicative, MonadT, ?>> appFn) { + return MonadT.super.zip(appFn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, MonadT, ?>>> lazyAppFn) { + return new Compose<>(mia) + .lazyZip(lazyAppFn.fmap(maybeT -> new Compose<>( + maybeT.>>coerce() + .>, + Monad>, M>>run()))) + .fmap(compose -> identityT(compose.getCompose())); + } + + /** + * {@inheritDoc} + */ + @Override + public IdentityT discardL(Applicative, ?>> appB) { + return MonadT.super.discardL(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public IdentityT discardR(Applicative, ?>> appB) { + return MonadT.super.discardR(appB).coerce(); + } + + @Override + public boolean equals(Object other) { + return other instanceof IdentityT && Objects.equals(mia, ((IdentityT) other).mia); + } + + @Override + public int hashCode() { + return Objects.hash(mia); + } + + @Override + public String toString() { + return "IdentityT{mia=" + mia + '}'; + } + + /** + * Static factory method for lifting a {@link Monad}<{@link Identity}<A>, M> into a + * {@link IdentityT}. + * + * @param mia the {@link Monad}<{@link Identity}<A>, M> + * @param the outer {@link Monad} unification parameter + * @param the carrier type + * @return the new {@link IdentityT}. + */ + public static , A> IdentityT identityT(Monad, M> mia) { + return new IdentityT<>(mia); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java new file mode 100644 index 000000000..d35ddc215 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java @@ -0,0 +1,126 @@ +package com.jnape.palatable.lambda.monad.transformer.builtin; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.Functor; +import com.jnape.palatable.lambda.functor.builtin.Compose; +import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.transformer.MonadT; + +import java.util.Objects; + +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; + +/** + * A {@link MonadT monad transformer} for {@link Lazy}. Note that {@link LazyT#flatMap(Fn1)} must force its value. + * + * @param the outer {@link Monad} + * @param the carrier type + */ +public class LazyT, A> implements MonadT, A> { + + private final Monad, M> mla; + + private LazyT(Monad, M> mla) { + this.mla = mla; + } + + /** + * {@inheritDoc} + */ + @Override + public >, FGA extends Monad> FGA run() { + return mla.fmap(Functor::coerce).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public LazyT flatMap(Fn1, ?>>> f) { + return new LazyT<>(mla.flatMap(lazyA -> f.apply(lazyA.value())., B>>coerce().run())); + } + + /** + * {@inheritDoc} + */ + @Override + public LazyT pure(B b) { + return new LazyT<>(mla.pure(lazy(b))); + } + + /** + * {@inheritDoc} + */ + @Override + public LazyT fmap(Fn1 fn) { + return MonadT.super.fmap(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public LazyT zip(Applicative, MonadT, ?>> appFn) { + return MonadT.super.zip(appFn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, MonadT, ?>>> lazyAppFn) { + return new Compose<>(mla) + .lazyZip(lazyAppFn.fmap(lazyT -> new Compose<>( + lazyT.>>coerce() + .>, + Monad>, M>>run()))) + .fmap(compose -> lazyT(compose.getCompose())); + } + + /** + * {@inheritDoc} + */ + @Override + public LazyT discardL(Applicative, ?>> appB) { + return MonadT.super.discardL(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public LazyT discardR(Applicative, ?>> appB) { + return MonadT.super.discardR(appB).coerce(); + } + + @Override + public boolean equals(Object other) { + return other instanceof LazyT && Objects.equals(mla, ((LazyT) other).mla); + } + + @Override + public int hashCode() { + return Objects.hash(mla); + } + + @Override + public String toString() { + return "LazyT{mla=" + mla + '}'; + } + + /** + * Static factory method for lifting a {@link Monad}<{@link Lazy}<A>, M> into a + * {@link LazyT}. + * + * @param mla the {@link Monad}<{@link Lazy}<A>, M> + * @param the outer {@link Monad} unification parameter + * @param the carrier type + * @return the new {@link LazyT} + */ + public static , A> LazyT lazyT(Monad, M> mla) { + return new LazyT<>(mla); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java new file mode 100644 index 000000000..7f1cf151f --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java @@ -0,0 +1,131 @@ +package com.jnape.palatable.lambda.monad.transformer.builtin; + +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.builtin.Compose; +import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.transformer.MonadT; + +import java.util.Objects; + +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; + +/** + * A {@link MonadT monad transformer} for {@link Maybe}. + * + * @param the outer {@link Monad} + * @param the carrier type + */ +public final class MaybeT, A> implements MonadT, A> { + + private final Monad, M> mma; + + private MaybeT(Monad, M> mma) { + this.mma = mma; + } + + /** + * {@inheritDoc} + */ + @Override + public >, FGA extends Monad> FGA run() { + return mma.fmap(Applicative::coerce).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public MaybeT fmap(Fn1 fn) { + return MonadT.super.fmap(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public MaybeT pure(B b) { + return maybeT(mma.pure(just(b))); + } + + /** + * {@inheritDoc} + */ + @Override + public MaybeT zip(Applicative, MonadT, ?>> appFn) { + return MonadT.super.zip(appFn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, MonadT, ?>>> lazyAppFn) { + return new Compose<>(mma) + .lazyZip(lazyAppFn.fmap(maybeT -> new Compose<>( + maybeT.>>coerce() + .>, Monad>, M>>run()))) + .fmap(compose -> maybeT(compose.getCompose())); + } + + /** + * {@inheritDoc} + */ + @Override + public MaybeT flatMap(Fn1, ?>>> f) { + return maybeT(mma.flatMap(ma -> ma + .match(constantly(mma.pure(nothing())), + a -> f.apply(a).>coerce().run()))); + } + + /** + * {@inheritDoc} + */ + @Override + public MaybeT discardL(Applicative, ?>> appB) { + return MonadT.super.discardL(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public MaybeT discardR(Applicative, ?>> appB) { + return MonadT.super.discardR(appB).coerce(); + } + + @Override + public boolean equals(Object other) { + return other instanceof MaybeT && Objects.equals(mma, ((MaybeT) other).mma); + } + + @Override + public int hashCode() { + return Objects.hash(mma); + } + + @Override + public String toString() { + return "MaybeT{" + + "mma=" + mma + + '}'; + } + + /** + * Static factory method for lifting a {@link Monad}<{@link Maybe}<A>, M> into a + * {@link MaybeT}. + * + * @param mma the {@link Monad}<{@link Maybe}<A>, M> + * @param the outer {@link Monad} unification parameter + * @param the carrier type + * @return the {@link MaybeT} + */ + public static , A> MaybeT maybeT(Monad, M> mma) { + return new MaybeT<>(mma); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/Monoid.java b/src/main/java/com/jnape/palatable/lambda/monoid/Monoid.java index 6cdf12b1e..8ecf83775 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/Monoid.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/Monoid.java @@ -1,18 +1,19 @@ package com.jnape.palatable.lambda.monoid; +import com.jnape.palatable.lambda.functions.Fn0; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.Map; import com.jnape.palatable.lambda.functions.builtin.fn2.ReduceLeft; import com.jnape.palatable.lambda.functions.builtin.fn2.ReduceRight; import com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.semigroup.Semigroup; -import java.util.function.Function; -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.functor.builtin.Lazy.lazy; /** * A {@link Monoid} is the pairing of a {@link Semigroup} with an identity element. @@ -57,15 +58,15 @@ default A reduceRight(Iterable as) { * Iterable<A> (that is, an Iterable of elements this monoid is formed over), then * reduce the result from left to right. Under algebraic data types, this is isomorphic to a flatMap. * + * @param the input Iterable element type * @param fn the mapping function from A to B * @param bs the Iterable of Bs - * @param the input Iterable element type * @return the folded result under this Monoid * @see Map * @see Monoid#reduceLeft(Iterable) */ - default A foldMap(Function fn, Iterable bs) { - return FoldLeft.foldLeft(this.toBiFunction(), identity(), map(fn, bs)); + default A foldMap(Fn1 fn, Iterable bs) { + return FoldLeft.foldLeft(this, identity(), map(fn, bs)); } /** @@ -80,8 +81,8 @@ default A foldLeft(A a, Iterable as) { * {@inheritDoc} */ @Override - default A foldRight(A a, Iterable as) { - return flip().foldMap(id(), reverse(cons(a, as))); + default Lazy foldRight(A a, Iterable as) { + return lazy(() -> flip().foldMap(id(), reverse(cons(a, as)))); } /** @@ -108,21 +109,21 @@ public A identity() { } @Override - public A apply(A x, A y) { + public A checkedApply(A x, A y) { return semigroup.apply(x, y); } }; } - static Monoid monoid(Semigroup semigroup, Supplier identitySupplier) { + static Monoid monoid(Semigroup semigroup, Fn0 identityFn0) { return new Monoid() { @Override public A identity() { - return identitySupplier.get(); + return identityFn0.apply(); } @Override - public A apply(A x, A y) { + public A checkedApply(A x, A y) { return semigroup.apply(x, y); } }; diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/AddAll.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/AddAll.java index 6cce48bfd..219763fd3 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/AddAll.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/AddAll.java @@ -1,13 +1,12 @@ package com.jnape.palatable.lambda.monoid.builtin; +import com.jnape.palatable.lambda.functions.Fn0; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft; import com.jnape.palatable.lambda.functions.specialized.MonoidFactory; import com.jnape.palatable.lambda.monoid.Monoid; import java.util.Collection; -import java.util.function.Function; -import java.util.function.Supplier; import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; @@ -19,23 +18,23 @@ * * @see Monoid */ -public final class AddAll> implements MonoidFactory, C> { +public final class AddAll> implements MonoidFactory, C> { - private static final AddAll INSTANCE = new AddAll(); + private static final AddAll INSTANCE = new AddAll<>(); private AddAll() { } @Override - public Monoid apply(Supplier cSupplier) { + public Monoid checkedApply(Fn0 cFn0) { return new Monoid() { @Override public C identity() { - return cSupplier.get(); + return cFn0.apply(); } @Override - public C apply(C xs, C ys) { + public C checkedApply(C xs, C ys) { C c = identity(); c.addAll(xs); c.addAll(ys); @@ -43,7 +42,7 @@ public C apply(C xs, C ys) { } @Override - public C foldMap(Function fn, Iterable bs) { + public C foldMap(Fn1 fn, Iterable bs) { return FoldLeft.foldLeft((x, y) -> { x.addAll(y); return x; @@ -54,18 +53,18 @@ public C foldMap(Function fn, Iterable bs) { @SuppressWarnings("unchecked") public static > AddAll addAll() { - return INSTANCE; + return (AddAll) INSTANCE; } - public static > Monoid addAll(Supplier collectionSupplier) { - return AddAll.addAll().apply(collectionSupplier); + public static > Monoid addAll(Fn0 collectionFn0) { + return AddAll.addAll().apply(collectionFn0); } - public static > Fn1 addAll(Supplier collectionSupplier, C xs) { - return addAll(collectionSupplier).apply(xs); + public static > Fn1 addAll(Fn0 collectionFn0, C xs) { + return addAll(collectionFn0).apply(xs); } - public static > C addAll(Supplier collectionSupplier, C xs, C ys) { - return addAll(collectionSupplier, xs).apply(ys); + public static > C addAll(Fn0 collectionFn0, C xs, C ys) { + return addAll(collectionFn0, xs).apply(ys); } } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/And.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/And.java index 3465ca0f8..2ce32994c 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/And.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/And.java @@ -4,8 +4,6 @@ import com.jnape.palatable.lambda.functions.specialized.BiPredicate; import com.jnape.palatable.lambda.monoid.Monoid; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Not.not; import static com.jnape.palatable.lambda.functions.builtin.fn2.Find.find; @@ -29,20 +27,15 @@ public Boolean identity() { } @Override - public Boolean apply(Boolean x, Boolean y) { + public Boolean checkedApply(Boolean x, Boolean y) { return x && y; } @Override - public Boolean foldMap(Function fn, Iterable bs) { + public Boolean foldMap(Fn1 fn, Iterable bs) { return find(not(fn), bs).fmap(constantly(false)).orElse(true); } - @Override - public boolean test(Boolean x, Boolean y) { - return apply(x, y); - } - @Override public And flip() { return this; diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Collapse.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Collapse.java index 51cf36970..7713431b5 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Collapse.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Collapse.java @@ -23,20 +23,21 @@ */ public final class Collapse<_1, _2> implements BiMonoidFactory, Monoid<_2>, Tuple2<_1, _2>> { - private static final Collapse INSTANCE = new Collapse(); + private static final Collapse INSTANCE = new Collapse<>(); private Collapse() { } @Override - public Monoid> apply(Monoid<_1> _1Monoid, Monoid<_2> _2Monoid) { - Semigroup> semigroup = com.jnape.palatable.lambda.semigroup.builtin.Collapse.collapse(_1Monoid, _2Monoid); - return Monoid.>monoid(semigroup, () -> tuple(_1Monoid.identity(), _2Monoid.identity())); + public Monoid> checkedApply(Monoid<_1> _1Monoid, Monoid<_2> _2Monoid) { + return Monoid.>monoid( + com.jnape.palatable.lambda.semigroup.builtin.Collapse.collapse(_1Monoid, _2Monoid), + () -> tuple(_1Monoid.identity(), _2Monoid.identity())); } @SuppressWarnings("unchecked") public static <_1, _2> Collapse<_1, _2> collapse() { - return INSTANCE; + return (Collapse<_1, _2>) INSTANCE; } public static <_1, _2> MonoidFactory, Tuple2<_1, _2>> collapse(Monoid<_1> _1Monoid) { diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Compose.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Compose.java index ca27bb28f..dbffbe748 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Compose.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Compose.java @@ -6,8 +6,8 @@ import com.jnape.palatable.lambda.semigroup.Semigroup; import java.util.concurrent.CompletableFuture; -import java.util.function.Supplier; +import static com.jnape.palatable.lambda.functions.Fn0.fn0; import static com.jnape.palatable.lambda.monoid.Monoid.monoid; import static java.util.concurrent.CompletableFuture.completedFuture; @@ -24,20 +24,20 @@ */ public final class Compose implements MonoidFactory, CompletableFuture> { - private static final Compose INSTANCE = new Compose(); + private static final Compose INSTANCE = new Compose<>(); private Compose() { } @Override - public Monoid> apply(Monoid aMonoid) { + public Monoid> checkedApply(Monoid aMonoid) { return monoid(com.jnape.palatable.lambda.semigroup.builtin.Compose.compose(aMonoid), - (Supplier>) () -> completedFuture(aMonoid.identity())); + fn0(() -> completedFuture(aMonoid.identity()))); } @SuppressWarnings("unchecked") public static Compose compose() { - return INSTANCE; + return (Compose) INSTANCE; } public static Monoid> compose(Monoid aMonoid) { diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Concat.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Concat.java index 2d164bbdc..83c7c31c8 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Concat.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Concat.java @@ -1,11 +1,10 @@ package com.jnape.palatable.lambda.monoid.builtin; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.iteration.ConcatenatingIterable; +import com.jnape.palatable.lambda.internal.iteration.ConcatenatingIterable; import com.jnape.palatable.lambda.monoid.Monoid; import java.util.Collections; -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; @@ -17,7 +16,7 @@ */ public final class Concat implements Monoid> { - private static final Concat INSTANCE = new Concat(); + private static final Concat INSTANCE = new Concat<>(); private Concat() { } @@ -28,18 +27,18 @@ public Iterable identity() { } @Override - public Iterable apply(Iterable xs, Iterable ys) { + public Iterable checkedApply(Iterable xs, Iterable ys) { return new ConcatenatingIterable<>(xs, ys); } @Override - public Iterable foldMap(Function> fn, Iterable bs) { + public Iterable foldMap(Fn1> fn, Iterable bs) { return flatten(map(fn, bs)); } @SuppressWarnings("unchecked") public static Concat concat() { - return INSTANCE; + return (Concat) INSTANCE; } public static Fn1, Iterable> concat(Iterable xs) { diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Endo.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Endo.java new file mode 100644 index 000000000..990689535 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Endo.java @@ -0,0 +1,57 @@ +package com.jnape.palatable.lambda.monoid.builtin; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.monoid.Monoid; + +import static com.jnape.palatable.lambda.functions.Fn2.curried; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; + +/** + * A {@link Monoid} formed by {@link Fn1} under composition. + * + * @param the input/output type to the {@link Fn1} + */ +public final class Endo implements Monoid> { + + private static final Endo INSTANCE = new Endo<>(); + + private Endo() { + } + + public A apply(Fn1 f, Fn1 g, A a) { + return apply(f, g).apply(a); + } + + @Override + public Fn1 identity() { + return id(); + } + + @Override + public Fn1 checkedApply(Fn1 f, Fn1 g) { + return f.fmap(g); + } + + @Override + public Fn2, A, A> apply(Fn1 f) { + return curried(Monoid.super.apply(f)); + } + + @SuppressWarnings("unchecked") + public static Endo endo() { + return (Endo) INSTANCE; + } + + public static Fn2, A, A> endo(Fn1 f) { + return Endo.endo().apply(f); + } + + public static Fn1 endo(Fn1 f, Fn1 g) { + return endo(f).apply(g); + } + + public static A endo(Fn1 f, Fn1 g, A a) { + return endo(f, g).apply(a); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/First.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/First.java index cb3b65f4c..9c44abca9 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/First.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/First.java @@ -4,8 +4,6 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.monoid.Monoid; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.functions.builtin.fn1.CatMaybes.catMaybes; import static com.jnape.palatable.lambda.functions.builtin.fn1.Head.head; @@ -23,7 +21,7 @@ */ public final class First implements Monoid> { - private static final First INSTANCE = new First(); + private static final First INSTANCE = new First<>(); private First() { } @@ -34,18 +32,18 @@ public Maybe identity() { } @Override - public Maybe apply(Maybe x, Maybe y) { + public Maybe checkedApply(Maybe x, Maybe y) { return x.fmap(Maybe::just).orElse(y); } @Override - public Maybe foldMap(Function> fn, Iterable bs) { + public Maybe foldMap(Fn1> fn, Iterable bs) { return head(catMaybes(map(fn, bs))); } @SuppressWarnings("unchecked") public static First first() { - return INSTANCE; + return (First) INSTANCE; } public static Fn1, Maybe> first(Maybe x) { diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Join.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Join.java index 9f3713283..571bcbe73 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Join.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Join.java @@ -21,7 +21,7 @@ public String identity() { } @Override - public String apply(String x, String y) { + public String checkedApply(String x, String y) { return x + y; } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Last.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Last.java index bb039c09a..8b0c91073 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Last.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Last.java @@ -19,7 +19,7 @@ * @see Maybe */ public final class Last implements Monoid> { - private static final Last INSTANCE = new Last(); + private static final Last INSTANCE = new Last<>(); private Last() { } @@ -30,13 +30,13 @@ public Maybe identity() { } @Override - public Maybe apply(Maybe x, Maybe y) { + public Maybe checkedApply(Maybe x, Maybe y) { return first(y, x); } @SuppressWarnings("unchecked") public static Last last() { - return INSTANCE; + return (Last) INSTANCE; } public static Fn1, Maybe> last(Maybe x) { diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/LeftAll.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/LeftAll.java index 5026328fb..ca2f4634b 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/LeftAll.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/LeftAll.java @@ -29,20 +29,20 @@ */ public final class LeftAll implements MonoidFactory, Either> { - private static final LeftAll INSTANCE = new LeftAll(); + private static final LeftAll INSTANCE = new LeftAll<>(); private LeftAll() { } @Override - public Monoid> apply(Monoid lMonoid) { + public Monoid> checkedApply(Monoid lMonoid) { Semigroup> semigroup = com.jnape.palatable.lambda.semigroup.builtin.LeftAll.leftAll(lMonoid); return Monoid.>monoid(semigroup, () -> left(lMonoid.identity())); } @SuppressWarnings("unchecked") public static LeftAll leftAll() { - return INSTANCE; + return (LeftAll) INSTANCE; } public static Monoid> leftAll(Monoid lMonoid) { diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/LeftAny.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/LeftAny.java index a9035d67c..461738188 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/LeftAny.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/LeftAny.java @@ -29,20 +29,20 @@ */ public final class LeftAny implements MonoidFactory, Either> { - private static final LeftAny INSTANCE = new LeftAny(); + private static final LeftAny INSTANCE = new LeftAny<>(); private LeftAny() { } @Override - public Monoid> apply(Monoid lMonoid) { + public Monoid> checkedApply(Monoid lMonoid) { Semigroup> semigroup = com.jnape.palatable.lambda.semigroup.builtin.LeftAny.leftAny(lMonoid); return Monoid.>monoid(semigroup, () -> left(lMonoid.identity())); } @SuppressWarnings("unchecked") public static LeftAny leftAny() { - return INSTANCE; + return (LeftAny) INSTANCE; } public static Monoid> leftAny(Monoid lMonoid) { diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Merge.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Merge.java index 798b6041a..83b3afa41 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Merge.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Merge.java @@ -22,20 +22,20 @@ */ public final class Merge implements BiMonoidFactory, Monoid, Either> { - private static final Merge INSTANCE = new Merge(); + private static final Merge INSTANCE = new Merge<>(); private Merge() { } @Override - public Monoid> apply(Semigroup lSemigroup, Monoid rMonoid) { + public Monoid> checkedApply(Semigroup lSemigroup, Monoid rMonoid) { Semigroup> semigroup = com.jnape.palatable.lambda.semigroup.builtin.Merge.merge(lSemigroup, rMonoid); return Monoid.>monoid(semigroup, () -> right(rMonoid.identity())); } @SuppressWarnings("unchecked") public static Merge merge() { - return INSTANCE; + return (Merge) INSTANCE; } public static MonoidFactory, Either> merge(Semigroup lSemigroup) { diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeMaps.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeMaps.java index 104d6f7d5..0f5c5fcc9 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeMaps.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeMaps.java @@ -1,5 +1,6 @@ package com.jnape.palatable.lambda.monoid.builtin; +import com.jnape.palatable.lambda.functions.Fn0; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.specialized.BiMonoidFactory; import com.jnape.palatable.lambda.functions.specialized.MonoidFactory; @@ -8,7 +9,6 @@ import java.util.Map; import java.util.function.BiFunction; -import java.util.function.Supplier; /** * A {@link Monoid} instance formed by {@link java.util.Map#merge(Object, Object, BiFunction)} and a semigroup over @@ -19,43 +19,43 @@ * @see Monoid * @see java.util.Map */ -public final class MergeMaps implements BiMonoidFactory>, Semigroup, Map> { +public final class MergeMaps implements BiMonoidFactory>, Semigroup, Map> { - private static final MergeMaps INSTANCE = new MergeMaps(); + private static final MergeMaps INSTANCE = new MergeMaps<>(); private MergeMaps() { } @Override - public Monoid> apply(Supplier> mSupplier, Semigroup semigroup) { + public Monoid> checkedApply(Fn0> mFn0, Semigroup semigroup) { return Monoid.>monoid((x, y) -> { - Map copy = mSupplier.get(); + Map copy = mFn0.apply(); copy.putAll(x); y.forEach((k, v) -> copy.merge(k, v, semigroup.toBiFunction())); return copy; - }, mSupplier); + }, mFn0); } @SuppressWarnings("unchecked") public static MergeMaps mergeMaps() { - return INSTANCE; + return (MergeMaps) INSTANCE; } - public static MonoidFactory, Map> mergeMaps(Supplier> mSupplier) { - return MergeMaps.mergeMaps().apply(mSupplier); + public static MonoidFactory, Map> mergeMaps(Fn0> mFn0) { + return MergeMaps.mergeMaps().apply(mFn0); } - public static Monoid> mergeMaps(Supplier> mSupplier, Semigroup semigroup) { - return mergeMaps(mSupplier).apply(semigroup); + public static Monoid> mergeMaps(Fn0> mFn0, Semigroup semigroup) { + return mergeMaps(mFn0).apply(semigroup); } - public static Fn1, Map> mergeMaps(Supplier> mSupplier, Semigroup semigroup, + public static Fn1, Map> mergeMaps(Fn0> mFn0, Semigroup semigroup, Map x) { - return mergeMaps(mSupplier, semigroup).apply(x); + return mergeMaps(mFn0, semigroup).apply(x); } - public static Map mergeMaps(Supplier> mSupplier, Semigroup semigroup, Map x, + public static Map mergeMaps(Fn0> mFn0, Semigroup semigroup, Map x, Map y) { - return mergeMaps(mSupplier, semigroup, x).apply(y); + return mergeMaps(mFn0, semigroup, x).apply(y); } } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Or.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Or.java index a8157d0fb..84c45f5f4 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Or.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Or.java @@ -4,8 +4,6 @@ import com.jnape.palatable.lambda.functions.specialized.BiPredicate; import com.jnape.palatable.lambda.monoid.Monoid; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn2.Find.find; @@ -28,18 +26,13 @@ public Boolean identity() { } @Override - public Boolean apply(Boolean x, Boolean y) { + public Boolean checkedApply(Boolean x, Boolean y) { return x || y; } @Override - public boolean test(Boolean x, Boolean y) { - return apply(x, y); - } - - @Override - public Boolean foldMap(Function fn, Iterable bs) { - return find(fn::apply, bs).fmap(constantly(true)).orElse(false); + public Boolean foldMap(Fn1 fn, Iterable bs) { + return find(fn, bs).fmap(constantly(true)).orElse(false); } @Override diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Present.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Present.java index cccf15d1b..71dc4e95f 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Present.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Present.java @@ -29,20 +29,20 @@ */ public final class Present implements MonoidFactory, Maybe> { - private static final Present INSTANCE = new Present<>(); + private static final Present INSTANCE = new Present<>(); private Present() { } @Override - public Monoid> apply(Semigroup aSemigroup) { + public Monoid> checkedApply(Semigroup aSemigroup) { return monoid((maybeX, maybeY) -> first(maybeX.fmap(x -> maybeY.fmap(aSemigroup.apply(x)).orElse(x)), maybeY), nothing()); } @SuppressWarnings("unchecked") public static Present present() { - return INSTANCE; + return (Present) INSTANCE; } public static Monoid> present(Semigroup semigroup) { diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/PutAll.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/PutAll.java index b5c4e7ef8..b3462f175 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/PutAll.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/PutAll.java @@ -25,7 +25,7 @@ public HMap identity() { } @Override - public HMap apply(HMap x, HMap y) { + public HMap checkedApply(HMap x, HMap y) { return x.putAll(y); } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RightAll.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RightAll.java index f68fb82e2..6968ea72c 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RightAll.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RightAll.java @@ -33,7 +33,7 @@ private RightAll() { } @Override - public Monoid> apply(Monoid rMonoid) { + public Monoid> checkedApply(Monoid rMonoid) { Semigroup> semigroup = com.jnape.palatable.lambda.semigroup.builtin.RightAll.rightAll(rMonoid); return Monoid.>monoid(semigroup, () -> right(rMonoid.identity())); } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RightAny.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RightAny.java index f357d5da4..277ec5163 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RightAny.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RightAny.java @@ -29,20 +29,20 @@ */ public final class RightAny implements MonoidFactory, Either> { - private static final RightAny INSTANCE = new RightAny(); + private static final RightAny INSTANCE = new RightAny<>(); private RightAny() { } @Override - public Monoid> apply(Monoid rMonoid) { + public Monoid> checkedApply(Monoid rMonoid) { Semigroup> semigroup = com.jnape.palatable.lambda.semigroup.builtin.RightAny.rightAny(rMonoid); return Monoid.>monoid(semigroup, () -> right(rMonoid.identity())); } @SuppressWarnings("unchecked") public static RightAny rightAny() { - return INSTANCE; + return (RightAny) INSTANCE; } public static Monoid> rightAny(Monoid rMonoid) { diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RunAll.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RunAll.java index 8e3c0d869..7533f9c41 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RunAll.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RunAll.java @@ -1,12 +1,12 @@ package com.jnape.palatable.lambda.monoid.builtin; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.IO; import com.jnape.palatable.lambda.functions.specialized.MonoidFactory; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monoid.Monoid; import com.jnape.palatable.lambda.semigroup.Semigroup; -import static com.jnape.palatable.lambda.functions.IO.io; +import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.lambda.monoid.Monoid.monoid; /** @@ -17,20 +17,20 @@ */ public final class RunAll implements MonoidFactory, IO> { - private static final RunAll INSTANCE = new RunAll(); + private static final RunAll INSTANCE = new RunAll<>(); private RunAll() { } @Override - public Monoid> apply(Monoid monoid) { + public Monoid> checkedApply(Monoid monoid) { Semigroup> semigroup = com.jnape.palatable.lambda.semigroup.builtin.RunAll.runAll(monoid); return monoid(semigroup, io(monoid.identity())); } @SuppressWarnings("unchecked") public static RunAll runAll() { - return INSTANCE; + return (RunAll) INSTANCE; } public static Monoid> runAll(Monoid monoid) { diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Trivial.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Trivial.java new file mode 100644 index 000000000..bf77b65f1 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Trivial.java @@ -0,0 +1,41 @@ +package com.jnape.palatable.lambda.monoid.builtin; + +import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.builtin.fn1.Constantly; +import com.jnape.palatable.lambda.monoid.Monoid; + +import static com.jnape.palatable.lambda.adt.Unit.UNIT; + +/** + * The trivial {@link Unit} {@link Monoid} formed under {@link Constantly constantly}. + */ +public final class Trivial implements Monoid { + + private static final Trivial INSTANCE = new Trivial(); + + private Trivial() { + } + + @Override + public Unit identity() { + return UNIT; + } + + @Override + public Unit checkedApply(Unit x, Unit y) throws Throwable { + return y; + } + + public static Trivial trivial() { + return INSTANCE; + } + + public static Fn1 trivial(Unit x) { + return trivial().apply(x); + } + + public static Unit trivial(Unit x, Unit y) { + return trivial(x).apply(y); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Union.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Union.java index d119e0a50..283bd2980 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Union.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Union.java @@ -2,7 +2,7 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn1.Distinct; -import com.jnape.palatable.lambda.iteration.UnioningIterable; +import com.jnape.palatable.lambda.internal.iteration.UnioningIterable; import com.jnape.palatable.lambda.monoid.Monoid; import java.util.Collections; @@ -15,7 +15,7 @@ */ public final class Union implements Monoid> { - private static final Union INSTANCE = new Union(); + private static final Union INSTANCE = new Union<>(); private Union() { } @@ -26,13 +26,13 @@ public Iterable identity() { } @Override - public Iterable apply(Iterable xs, Iterable ys) { + public Iterable checkedApply(Iterable xs, Iterable ys) { return new UnioningIterable<>(xs, ys); } @SuppressWarnings("unchecked") public static Union union() { - return INSTANCE; + return (Union) INSTANCE; } public static Fn1, Iterable> union(Iterable xs) { diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Xor.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Xor.java index 860df1e6f..8ed724ad6 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Xor.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Xor.java @@ -26,15 +26,10 @@ public Boolean identity() { } @Override - public Boolean apply(Boolean x, Boolean y) { + public Boolean checkedApply(Boolean x, Boolean y) { return x ^ y; } - @Override - public boolean test(Boolean x, Boolean y) { - return apply(x, y); - } - @Override public Xor flip() { return this; diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Iso.java b/src/main/java/com/jnape/palatable/lambda/optics/Iso.java new file mode 100644 index 000000000..feb59212c --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/optics/Iso.java @@ -0,0 +1,377 @@ +package com.jnape.palatable.lambda.optics; + +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.Functor; +import com.jnape.palatable.lambda.functor.Profunctor; +import com.jnape.palatable.lambda.functor.builtin.Exchange; +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.optics.functions.Over; +import com.jnape.palatable.lambda.optics.functions.Set; +import com.jnape.palatable.lambda.optics.functions.View; + +import static com.jnape.palatable.lambda.functions.Fn1.fn1; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.optics.Iso.Simple.adapt; +import static com.jnape.palatable.lambda.optics.Lens.lens; +import static com.jnape.palatable.lambda.optics.Optic.optic; +import static com.jnape.palatable.lambda.optics.functions.View.view; + +/** + * An {@link Iso} (short for "isomorphism") is an invertible {@link Lens}: an {@link Optic} encoding of a + * bi-directional focusing of two types, and like {@link Lens}es, can be {@link View}ed, + * {@link Set}, and {@link Over updated}. + *

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

+ * {@code
+ * Iso stringIntIso = Iso.iso(Integer::parseInt, Object::toString);
+ * Integer asInt = view(stringIntIso, "123"); // 123
+ * String asString = view(stringIntIso.mirror(), 123); // "123"
+ * }
+ * 
+ * In the previous example, stringIntIso can be viewed as an + * {@link Optic}<String, String, Integer, Integer>, and can be {@link Iso#mirror}ed and + * viewed as a {@link Optic}<Integer, Integer, String, String>. + *

+ * As with {@link Lens}, variance is supported between S/T and A/B, and where these pairs do + * not vary, a {@link Simple} iso can be used (for instance, in the previous example, stringIntIso could + * have had the simplified Iso.Simple<String, Integer> type). + *

+ * For more information, read about + * isos. + * + * @param the larger type for focusing + * @param the larger type for mirrored focusing + * @param the smaller type for focusing + * @param the smaller type for mirrored focusing + * @see Optic + * @see Lens + */ +@FunctionalInterface +public interface Iso extends + Optic, Functor, S, T, A, B>, + Monad>, + Profunctor> { + + /** + * Convert this {@link Iso} into a {@link Lens}. + * + * @return the equivalent lens + */ + default Lens toLens() { + return lens(this); + } + + /** + * Flip this {@link Iso} around. + * + * @return the mirrored {@link Iso} + */ + default Iso mirror() { + return unIso().into((sa, bt) -> iso(bt, sa)); + } + + /** + * Destructure this {@link Iso} into the two functions S -< A and B -< T that + * constitute the isomorphism. + * + * @return the destructured iso + */ + default Tuple2, Fn1> unIso() { + return Tuple2.fill(this., Identity, + Identity, + Identity, + Exchange>, + Exchange>>apply(new Exchange<>(id(), Identity::new)).diMapR(Identity::runIdentity)) + .biMap(e -> fn1(e.sa()), e -> fn1(e.bt())); + } + + /** + * {@inheritDoc} + */ + @Override + default Iso fmap(Fn1 fn) { + return Monad.super.fmap(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default Iso pure(U u) { + return iso(view(this), constantly(u)); + } + + /** + * {@inheritDoc} + */ + @Override + default Iso zip(Applicative, Iso> appFn) { + return Monad.super.zip(appFn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default Iso discardL(Applicative> appB) { + return Monad.super.discardL(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default Iso discardR(Applicative> appB) { + return Monad.super.discardR(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default Iso flatMap(Fn1>> fn) { + //noinspection RedundantTypeArguments + return unIso().fmap(bt -> Fn2.curried( + fn1(bt.fmap(fn.>fmap(Monad>::coerce)) + .fmap(Iso::unIso) + .fmap(Tuple2::_2) + .fmap(Fn1::fn1)))) + .fmap(Fn2::uncurry) + .fmap(bbu -> bbu.diMapL(Tuple2::fill)) + .into(Iso::iso); + } + + /** + * {@inheritDoc} + */ + @Override + default Iso diMapL(Fn1 fn) { + return (Iso) Profunctor.super.diMapL(fn); + } + + /** + * {@inheritDoc} + */ + @Override + default Iso diMapR(Fn1 fn) { + return (Iso) Profunctor.super.diMapR(fn); + } + + /** + * {@inheritDoc} + */ + @Override + default Iso diMap(Fn1 lFn, + Fn1 rFn) { + return this.mapS(lFn).mapT(rFn); + } + + /** + * {@inheritDoc} + */ + @Override + default Iso contraMap(Fn1 fn) { + return (Iso) Profunctor.super.contraMap(fn); + } + + /** + * {@inheritDoc} + */ + @Override + default Iso mapS(Fn1 fn) { + return iso(Optic.super.mapS(fn)); + } + + /** + * {@inheritDoc} + */ + @Override + default Iso mapT(Fn1 fn) { + return iso(Optic.super.mapT(fn)); + } + + /** + * {@inheritDoc} + */ + @Override + default Iso mapA(Fn1 fn) { + return iso(Optic.super.mapA(fn)); + } + + /** + * {@inheritDoc} + */ + @Override + default Iso mapB(Fn1 fn) { + return iso(Optic.super.mapB(fn)); + } + + /** + * {@inheritDoc} + */ + @Override + default Iso andThen(Optic, ? super Functor, A, B, Z, C> f) { + return iso(Optic.super.andThen(f)); + } + + /** + * {@inheritDoc} + */ + @Override + default Iso compose(Optic, ? super Functor, R, U, S, T> g) { + return iso(Optic.super.compose(g)); + } + + /** + * Static factory method for creating an iso from a function and it's inverse. + * + * @param f the function + * @param g f's inverse + * @param the larger type for focusing + * @param the larger type for mirrored focusing + * @param the smaller type for focusing + * @param the smaller type for mirrored focusing + * @return the iso + */ + static Iso iso(Fn1 f, Fn1 g) { + return iso(optic(pafb -> pafb.diMap(f, fb -> fb.fmap(g)))); + } + + /** + * Promote an optic with compatible bounds to an {@link Iso}. + * + * @param optic the {@link Optic} + * @param the larger type for focusing + * @param the larger type for mirrored focusing + * @param the smaller type for focusing + * @param the smaller type for mirrored focusing + * @return the {@link Iso} + */ + static Iso iso( + Optic, ? super Functor, S, T, A, B> optic) { + return new Iso() { + @Override + public >, + CoF extends Functor>, FB extends Functor, + FT extends Functor, PAFB extends Profunctor, + PSFT extends Profunctor> PSFT apply(PAFB pafb) { + return optic.apply(pafb); + } + }; + } + + /** + * Static factory method for creating a simple {@link Iso} from a function and its inverse. + * + * @param f a function + * @param g f's inverse + * @param one side of the isomorphism + * @param the other side of the isomorphism + * @return the simple iso + */ + static Iso.Simple simpleIso(Fn1 f, Fn1 g) { + return adapt(iso(f, g)); + } + + /** + * A convenience type with a simplified type signature for common isos with both unified "larger" values and + * unified "smaller" values. + * + * @param the type of both "larger" values + * @param the type of both "smaller" values + */ + @FunctionalInterface + interface Simple extends Iso, Optic.Simple, Functor, S, A> { + + /** + * Compose two simple isos from right to left. + * + * @param g the other simple iso + * @param the other simple iso' larger type + * @return the composed simple iso + */ + @SuppressWarnings("overloads") + default Iso.Simple compose(Iso.Simple g) { + return Iso.Simple.adapt(Iso.super.compose(g)); + } + + /** + * Compose two simple isos from left to right. + * + * @param f the other simple iso + * @param the other simple iso' smaller type + * @return the composed simple iso + */ + @SuppressWarnings("overloads") + default Iso.Simple andThen(Iso.Simple f) { + return Iso.Simple.adapt(f.compose(this)); + } + + /** + * {@inheritDoc} + */ + @Override + default Iso.Simple mirror() { + return Iso.Simple.adapt(Iso.super.mirror()); + } + + /** + * {@inheritDoc} + */ + @Override + default Lens.Simple toLens() { + return Lens.Simple.adapt(Iso.super.toLens()); + } + + /** + * {@inheritDoc} + */ + @Override + default Iso.Simple discardR(Applicative> appB) { + return Iso.Simple.adapt(Iso.super.discardR(appB)); + } + + /** + * {@inheritDoc} + */ + @Override + default Iso.Simple andThen(Optic.Simple, ? super Functor, A, B> f) { + return Iso.Simple.adapt(Iso.super.andThen(f)); + } + + /** + * {@inheritDoc} + */ + @Override + default Iso.Simple compose(Optic.Simple, ? super Functor, R, S> g) { + return Iso.Simple.adapt(Iso.super.compose(g)); + } + + /** + * Adapt an {@link Optic} with the right variance to an {@link Iso.Simple}. + * + * @param optic the optic + * @param S/T + * @param A/B + * @return the simple iso + */ + static Iso.Simple adapt( + Optic, ? super Functor, S, S, A, A> optic) { + return new Iso.Simple() { + @Override + public >, + CoF extends Functor>, FB extends Functor, + FT extends Functor, PAFB extends Profunctor, + PSFT extends Profunctor> PSFT apply(PAFB pafb) { + return optic.apply(pafb); + } + }; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/jnape/palatable/lambda/lens/Lens.java b/src/main/java/com/jnape/palatable/lambda/optics/Lens.java similarity index 59% rename from src/main/java/com/jnape/palatable/lambda/lens/Lens.java rename to src/main/java/com/jnape/palatable/lambda/optics/Lens.java index 3f832d351..48e16495c 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/Lens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Lens.java @@ -1,20 +1,18 @@ -package com.jnape.palatable.lambda.lens; +package com.jnape.palatable.lambda.optics; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.builtin.fn2.Both; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Functor; +import com.jnape.palatable.lambda.functor.Profunctor; import com.jnape.palatable.lambda.monad.Monad; -import java.util.function.BiFunction; -import java.util.function.Function; - -import static com.jnape.palatable.lambda.lens.Iso.iso; -import static com.jnape.palatable.lambda.lens.Lens.Simple.adapt; -import static com.jnape.palatable.lambda.lens.functions.Over.over; -import static com.jnape.palatable.lambda.lens.functions.Set.set; -import static com.jnape.palatable.lambda.lens.functions.View.view; +import static com.jnape.palatable.lambda.optics.Iso.iso; +import static com.jnape.palatable.lambda.optics.Lens.Simple.adapt; +import static com.jnape.palatable.lambda.optics.functions.Set.set; +import static com.jnape.palatable.lambda.optics.functions.View.view; /** * An approximation of van Laarhoven lenses. @@ -135,79 +133,126 @@ * @param the type of the "larger" value for putting * @param the type of the "smaller" value that is read * @param the type of the "smaller" update value + * @see Optic + * @see Iso */ @FunctionalInterface -public interface Lens extends LensLike { +public interface Lens extends + Optic, Functor, S, T, A, B>, + Monad>, + Profunctor> { + /** + * {@inheritDoc} + */ @Override - default Lens fmap(Function fn) { - return LensLike.super.fmap(fn).coerce(); + default Lens fmap(Fn1 fn) { + return Monad.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override default Lens pure(U u) { return lens(view(this), (s, b) -> u); } + /** + * {@inheritDoc} + */ @Override - default Lens zip(Applicative, LensLike> appFn) { - return LensLike.super.zip(appFn).coerce(); + default Lens zip(Applicative, Lens> appFn) { + return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ @Override - default Lens discardL(Applicative> appB) { - return LensLike.super.discardL(appB).coerce(); + default Lens discardL(Applicative> appB) { + return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override - default Lens discardR(Applicative> appB) { - return LensLike.super.discardR(appB).coerce(); + default Lens discardR(Applicative> appB) { + return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override - default Lens flatMap(Function>> f) { + default Lens flatMap(Fn1>> f) { + return lens(view(this), (s, b) -> set(f.apply(set(this, b, s)).>coerce(), b, s)); } + /** + * {@inheritDoc} + */ @Override - default Lens diMapL(Function fn) { - return LensLike.super.diMapL(fn).coerce(); + default Lens diMapL(Fn1 fn) { + return (Lens) Profunctor.super.diMapL(fn); } + /** + * {@inheritDoc} + */ @Override - default Lens diMapR(Function fn) { - return LensLike.super.diMapR(fn).coerce(); + default Lens diMapR(Fn1 fn) { + return (Lens) Profunctor.super.diMapR(fn); } + /** + * {@inheritDoc} + */ @Override - default Lens diMap(Function lFn, - Function rFn) { - return LensLike.super.diMap(lFn, rFn).coerce(); + default Lens diMap(Fn1 lFn, Fn1 rFn) { + return this.mapS(lFn).mapT(rFn); } + /** + * {@inheritDoc} + */ @Override - default Lens contraMap(Function fn) { - return LensLike.super.contraMap(fn).coerce(); + default Lens contraMap(Fn1 fn) { + return (Lens) Profunctor.super.contraMap(fn); } + /** + * {@inheritDoc} + */ @Override - default Lens mapS(Function fn) { - return lens(view(this).compose(fn), (r, b) -> set(this, b, fn.apply(r))); + default Lens mapS(Fn1 fn) { + return lens(Optic.super.mapS(fn)); } + /** + * {@inheritDoc} + */ @Override - default Lens mapT(Function fn) { - return fmap(fn); + default Lens mapT(Fn1 fn) { + return lens(Optic.super.mapT(fn)); } + /** + * {@inheritDoc} + */ @Override - default Lens mapA(Function fn) { - return andThen(lens(fn, (a, b) -> b)); + default Lens mapA(Fn1 fn) { + return lens(Optic.super.mapA(fn)); } + /** + * {@inheritDoc} + */ @Override - default Lens mapB(Function fn) { - return lens(view(this), (s, z) -> set(this, fn.apply(z), s)); + default Lens mapB(Fn1 fn) { + return lens(Optic.super.mapB(fn)); } /** @@ -220,14 +265,20 @@ default Iso toIso(S s) { return iso(view(this), set(this).flip().apply(s)); } + /** + * {@inheritDoc} + */ @Override - default Lens andThen(LensLike f) { - return lens(view(this).fmap(view(f)), (q, b) -> over(this, set(f, b), q)); + default Lens andThen(Optic, ? super Functor, A, B, C, D> f) { + return lens(Optic.super.andThen(f)); } + /** + * {@inheritDoc} + */ @Override - default Lens compose(LensLike g) { - return lens(view(g).fmap(view(this)), (q, b) -> over(g, set(this, b), q)); + default Lens compose(Optic, ? super Functor, R, U, S, T> g) { + return lens(Optic.super.compose(g)); } /** @@ -241,15 +292,35 @@ default Lens compose(LensLike g) { * @param the type of the "smaller" update value * @return the lens */ - static Lens lens(Function getter, - BiFunction setter) { + static Lens lens(Fn1 getter, + Fn2 setter) { + return lens(Optic., Functor, + S, T, A, B, + Functor>, + Functor>, + Fn1>>, + Fn1>>>optic(afb -> s -> afb.apply(getter.apply(s)) + .fmap(b -> setter.apply(s, b)))); + } + + /** + * Promote an optic with compatible bounds to a {@link Lens}. + * + * @param optic the {@link Optic} + * @param the type of the "larger" value for reading + * @param the type of the "larger" value for putting + * @param the type of the "smaller" value that is read + * @param the type of the "smaller" update value + * @return the {@link Lens} + */ + static Lens lens(Optic, ? super Functor, S, T, A, B> optic) { return new Lens() { @Override - @SuppressWarnings("unchecked") - public , FB extends Functor> FT apply( - Function fn, - S s) { - return (FT) fn.apply(getter.apply(s)).fmap(b -> setter.apply(s, b)); + public >, CoF extends Functor>, + FB extends Functor, FT extends Functor, + PAFB extends Profunctor, + PSFT extends Profunctor> PSFT apply(PAFB pafb) { + return optic.apply(pafb); } }; } @@ -263,8 +334,8 @@ public , FB extends Functor> F * @param the type of both "smaller" values * @return the lens */ - static Lens.Simple simpleLens(Function getter, - BiFunction setter) { + static Lens.Simple simpleLens(Fn1 getter, + Fn2 setter) { return adapt(lens(getter, setter)); } @@ -282,7 +353,7 @@ static Lens.Simple simpleLens(Function gett * @return the dual-focus lens */ static Lens, Tuple2> both(Lens f, Lens g) { - return lens(Both.both(view(f), view(g)), (s, cd) -> cd.biMap(set(f), set(g)).into(Fn1::compose).apply(s)); + return lens(Both.both(view(f), view(g)), (s, cd) -> cd.biMap(set(f), set(g)).into(Fn1::contraMap).apply(s)); } /** @@ -307,14 +378,22 @@ static Lens.Simple> both(Lens.Simple f, Lens.Sim * @param the type of both "smaller" values */ @FunctionalInterface - interface Simple extends Lens, LensLike.Simple { + interface Simple extends Lens, Optic.Simple, Functor, S, A> { - default Lens.Simple compose(LensLike.Simple g) { - return Lens.Simple.adapt(Lens.super.compose(g)); + /** + * {@inheritDoc} + */ + @Override + default Lens.Simple andThen(Optic.Simple, ? super Functor, A, B> f) { + return Lens.Simple.adapt(Lens.super.andThen(f)); } - default Lens.Simple andThen(LensLike.Simple f) { - return Lens.Simple.adapt(Lens.super.andThen(f)); + /** + * {@inheritDoc} + */ + @Override + default Lens.Simple compose(Optic.Simple, ? super Functor, R, S> g) { + return Lens.Simple.adapt(Lens.super.compose(g)); } /** @@ -325,9 +404,16 @@ default Lens.Simple andThen(LensLike.Simple f) { * @param A/B * @return the simple lens */ - @SuppressWarnings("unchecked") - static Lens.Simple adapt(Lens lens) { - return lens::apply; + static Lens.Simple adapt(Optic, ? super Functor, S, S, A, A> lens) { + return new Lens.Simple() { + @Override + public >, + CoF extends Functor>, FB extends Functor, + FT extends Functor, PAFB extends Profunctor, + PSFT extends Profunctor> PSFT apply(PAFB pafb) { + return lens.apply(pafb); + } + }; } /** diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Optic.java b/src/main/java/com/jnape/palatable/lambda/optics/Optic.java new file mode 100644 index 000000000..fb6ec0e59 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/optics/Optic.java @@ -0,0 +1,292 @@ +package com.jnape.palatable.lambda.optics; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.Functor; +import com.jnape.palatable.lambda.functor.Profunctor; + +/** + * A generic supertype representation for profunctor optics. + *

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

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

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

the {@link Profunctor} bound + * @param the {@link Functor} bound + * @param the left side of the output profunctor + * @param the right side's functor embedding of the output profunctor + * @param the left side of the input profunctor + * @param the right side's functor embedding of the input profunctor + * @param fixed functor over B for inference + * @param fixed functor over T for inference + * @param the input + * @param the output + * @return the {@link Optic} + */ + static

, + F extends Functor, + S, T, A, B, + FB extends Functor, + FT extends Functor, + PAFB extends Profunctor, + PSFT extends Profunctor> Optic optic(Fn1 fn) { + return new Optic() { + @Override + @SuppressWarnings("unchecked") + public , + CoF extends Functor, + CoFB extends Functor, + CoFT extends Functor, + CoPAFB extends Profunctor, + CoPSFT extends Profunctor> CoPSFT apply( + CoPAFB pafb) { + return (CoPSFT) fn.apply((PAFB) pafb); + } + }; + } + + /** + * Reframe an {@link Optic} according to covariant bounds. + * + * @param optic the {@link Optic} + * @param

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

, + F extends Functor, + S, T, A, B> Optic reframe(Optic optic) { + return Optic.optic(optic., + Functor, + Profunctor, ? extends P>, + Profunctor, ? extends P>>monomorphize()); + } + + /** + * An convenience type with a simplified signature for {@link Optic optics} with unified S/T and + * A/B types. + * + * @param

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

, F extends Functor, S, A> + extends Optic { + + /** + * Compose two simple optics from left to right. + * + * @param f the other simple optic + * @param the new left side and right side's functor embedding of the input profunctor + * @return the composed simple optic + */ + @SuppressWarnings("overloads") + default Optic.Simple andThen(Optic.Simple f) { + Optic composed = Optic.super.andThen(f); + return new Simple() { + @Override + public , CoF extends Functor, + FB extends Functor, FT extends Functor, + PAFB extends Profunctor, PSFT extends Profunctor> + PSFT apply(PAFB pafb) { + return composed.apply(pafb); + } + }; + } + + /** + * Compose two simple optics from right to left. + * + * @param g the other simple optic + * @param the new left side and right side's functor embedding of the output profunctor + * @return the composed simple optic + */ + @SuppressWarnings("overloads") + default Optic.Simple compose(Optic.Simple g) { + Optic composed = Optic.super.compose(g); + return new Simple() { + @Override + public , CoF extends Functor, + FB extends Functor, FT extends Functor, + PAFB extends Profunctor, PSFT extends Profunctor> + PSFT apply(PAFB pafb) { + return composed.apply(pafb); + } + }; + } + + /** + * Adapt an {@link Optic} with S/T and A/B unified into a {@link Simple simple optic}. + * + * @param optic the {@link Optic} + * @param

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

, + F extends Functor, + S, A> Simple adapt(Optic optic) { + return new Simple() { + @Override + public , CoF extends Functor, + FB extends Functor, FT extends Functor, + PAFB extends Profunctor, + PSFT extends Profunctor> PSFT apply(PAFB pafb) { + return optic.apply(pafb); + } + }; + } + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Prism.java b/src/main/java/com/jnape/palatable/lambda/optics/Prism.java new file mode 100644 index 000000000..d89ad3bfb --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/optics/Prism.java @@ -0,0 +1,326 @@ +package com.jnape.palatable.lambda.optics; + +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.choice.Choice2; +import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Pure; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.Cocartesian; +import com.jnape.palatable.lambda.functor.Functor; +import com.jnape.palatable.lambda.functor.Profunctor; +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.functor.builtin.Market; +import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.optics.functions.Matching; +import com.jnape.palatable.lambda.optics.functions.Pre; +import com.jnape.palatable.lambda.optics.functions.Re; +import com.jnape.palatable.lambda.optics.functions.View; + +import static com.jnape.palatable.lambda.adt.Either.left; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Downcast.downcast; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Upcast.upcast; +import static com.jnape.palatable.lambda.optics.Prism.Simple.adapt; +import static com.jnape.palatable.lambda.optics.functions.Matching.matching; +import static com.jnape.palatable.lambda.optics.functions.Re.re; + +/** + * Prisms are {@link Iso Isos} that can fail in one direction. Example: + *

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

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

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

, S, T, A, B> + extends Optic, S, T, A, B> { + + /** + * Given a {@link Pure} lifting function, fix this {@link ProtoOptic} to the given {@link Functor} and promote it to + * an {@link Optic}. + * + * @param pure the {@link Pure} lifting function + * @param the {@link Functor} bound + * @return the {@link Optic} + */ + > Optic toOptic(Pure pure); + + @Override + default , CoF extends Functor>, + FB extends Functor, FT extends Functor, + PAFB extends Profunctor, + PSFT extends Profunctor> PSFT apply(PAFB pafb) { + return toOptic(Pure.>pure(Identity::new)).apply(pafb); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/optics/functions/Matching.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/Matching.java new file mode 100644 index 000000000..04b03442f --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/Matching.java @@ -0,0 +1,46 @@ +package com.jnape.palatable.lambda.optics.functions; + +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.functor.builtin.Market; +import com.jnape.palatable.lambda.optics.Optic; + +public final class Matching implements + Fn2, ? super Identity, S, T, A, B>, S, Either> { + + private static final Matching INSTANCE = new Matching<>(); + + private Matching() { + } + + @Override + public Either checkedApply(Optic, ? super Identity, S, T, A, B> optic, S s) { + Market> market = new Market<>(Identity::new, Either::right); + return optic., + Identity, + Identity, + Identity, + Market>, + Market>> + apply(market).sta().apply(s) + .biMapL(Identity::runIdentity) + .match(Either::left, Either::right); + } + + @SuppressWarnings("unchecked") + public static Matching matching() { + return (Matching) INSTANCE; + } + + public static Fn1> matching( + Optic, ? super Identity, S, T, A, B> optic) { + return Matching.matching().apply(optic); + } + + public static Either matching( + Optic, ? super Identity, S, T, A, B> optic, S s) { + return matching(optic).apply(s); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/optics/functions/Over.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/Over.java new file mode 100644 index 000000000..1e76ec4ce --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/Over.java @@ -0,0 +1,59 @@ +package com.jnape.palatable.lambda.optics.functions; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functions.Fn3; +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.optics.Optic; + +/** + * Given an {@link Optic}, a function from A to B, and a "larger" value S, + * produce a T by retrieving the A from the S, applying the function, and + * updating the S with the B resulting from the function. + *

+ * This function is similar to {@link Set}, except that it allows the setting value B to be derived from + * S via function application, rather than provided. + * + * @param the type of the larger value + * @param the type of the larger updated value + * @param the type of the smaller retrieving value + * @param the type of the smaller setting value + * @see Set + * @see View + */ +public final class Over implements + Fn3, ? super Identity, S, T, A, B>, Fn1, S, T> { + + private static final Over INSTANCE = new Over<>(); + + private Over() { + } + + @Override + public T checkedApply(Optic, ? super Identity, S, T, A, B> optic, + Fn1 fn, + S s) { + return optic., Identity, Identity, Identity, Fn1>, Fn1>>apply( + a -> new Identity<>(fn.apply(a))).apply(s).runIdentity(); + } + + @SuppressWarnings("unchecked") + public static Over over() { + return (Over) INSTANCE; + } + + public static Fn2, S, T> over( + Optic, ? super Identity, S, T, A, B> optic) { + return Over.over().apply(optic); + } + + public static Fn1 over(Optic, ? super Identity, S, T, A, B> optic, + Fn1 fn) { + return over(optic).apply(fn); + } + + public static T over(Optic, ? super Identity, S, T, A, B> optic, + Fn1 fn, S s) { + return over(optic, fn).apply(s); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/optics/functions/Pre.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/Pre.java new file mode 100644 index 000000000..977788eac --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/Pre.java @@ -0,0 +1,60 @@ +package com.jnape.palatable.lambda.optics.functions; + +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Pure; +import com.jnape.palatable.lambda.functor.builtin.Const; +import com.jnape.palatable.lambda.optics.Optic; +import com.jnape.palatable.lambda.optics.ProtoOptic; + +import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.optics.Optic.reframe; + +/** + * Turn an {@link Optic} with a unary mapping that can be used for viewing some number of values into an {@link Optic} + * that views the first value, if it exists. + * + * @param the value to read from + * @param used for unification of the {@link Optic optic's} unused morphism + * @param the result to {@link Maybe maybe} read out + * @param used for unification of the {@link Optic optic's} unused morphism + */ +public final class Pre implements Fn1, ? super Const, ?>, S, T, A, B>, + Optic, Const, ?>, S, T, Maybe, B>> { + + private static final Pre INSTANCE = new Pre<>(); + + private Pre() { + } + + @Override + public Optic, Const, ?>, S, T, Maybe, B> checkedApply( + Optic, ? super Const, ?>, S, T, A, B> optic) { + Optic, ? super Const, ?>, S, T, Maybe, B> mappedOptic = optic.mapA(Maybe::just); + return reframe(mappedOptic); + } + + @SuppressWarnings("unchecked") + public static Pre pre() { + return (Pre) INSTANCE; + } + + @SuppressWarnings("overloads") + public static Optic, Const, ?>, S, T, Maybe, B> pre( + Optic, ? super Const, ?>, S, T, A, B> optic) { + return Pre.pre().apply(optic); + } + + @SuppressWarnings("overloads") + public static Optic, Const, ?>, S, T, Maybe, B> pre( + ProtoOptic, S, T, A, B> protoOptic) { + Optic, Const, ?>, S, T, A, B> optic = protoOptic + .toOptic(new Pure, ?>>() { + @Override + public Const, X> checkedApply(X x) { + return new Const<>(nothing()); + } + }); + return pre(optic); + } +} \ No newline at end of file diff --git a/src/main/java/com/jnape/palatable/lambda/optics/functions/Re.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/Re.java new file mode 100644 index 000000000..eeb36f5b8 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/Re.java @@ -0,0 +1,48 @@ +package com.jnape.palatable.lambda.optics.functions; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.builtin.Const; +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.functor.builtin.Tagged; +import com.jnape.palatable.lambda.optics.Iso; +import com.jnape.palatable.lambda.optics.Optic; +import com.jnape.palatable.lambda.optics.Prism; + +/** + * Turn an {@link Optic} with a unary mapping that can be used for setting (e.g. {@link Prism}, {@link Iso}) around for + * viewing through the other direction. + * + * @param used for unification of the {@link Optic optic's} unused morphism + * @param the result to read out + * @param used for unification of the {@link Optic optic's} unused morphism + * @param the value to read from + */ +public final class Re implements + Fn1, ? super Identity, S, T, A, B>, Optic, Const, B, B, T, T>> { + + private static final Re INSTANCE = new Re<>(); + + private Re() { + } + + @Override + public Optic, Const, B, B, T, T> checkedApply( + Optic, ? super Identity, S, T, A, B> optic) { + return Optic., Const, B, B, T, T, + Const, Const, + Fn1>, + Fn1>>optic(pafb -> b -> new Const<>(optic., Identity, Identity, + Identity, Tagged>, + Tagged>>apply(new Tagged<>(new Identity<>(b))).unTagged().runIdentity())); + } + + @SuppressWarnings("unchecked") + public static Re re() { + return (Re) INSTANCE; + } + + public static Optic, Const, B, B, T, T> re( + Optic, ? super Identity, S, T, A, B> optic) { + return Re.re().apply(optic); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/optics/functions/Set.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/Set.java new file mode 100644 index 000000000..7fdd16e56 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/Set.java @@ -0,0 +1,54 @@ +package com.jnape.palatable.lambda.optics.functions; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functions.Fn3; +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.optics.Optic; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.optics.functions.Over.over; + +/** + * Given an {@link Optic}, a "smaller" value B, and a "larger" value S, produce a + * T by lifting the {@link Optic} into the {@link Identity} functor. + *

+ * More idiomatically, this function can be used to treat an {@link Optic} as a "setter" of + * Bs on Ss, potentially producing a different "larger" value, T. + * + * @param the type of the larger value + * @param the type of the larger updated value + * @param the type of the smaller retrieving value (unused, but necessary for composition) + * @param the type of the smaller setting value + * @see Over + * @see View + */ +public final class Set implements Fn3, ? super Identity, S, T, A, B>, B, S, T> { + + private static final Set INSTANCE = new Set<>(); + + private Set() { + } + + @Override + public T checkedApply(Optic, ? super Identity, S, T, A, B> optic, B b, S s) { + return over(optic, constantly(b), s); + } + + @SuppressWarnings("unchecked") + public static Set set() { + return (Set) INSTANCE; + } + + public static Fn2 set(Optic, ? super Identity, S, T, A, B> optic) { + return Set.set().apply(optic); + } + + public static Fn1 set(Optic, ? super Identity, S, T, A, B> optic, B b) { + return set(optic).apply(b); + } + + public static T set(Optic, ? super Identity, S, T, A, B> optic, B b, S s) { + return set(optic, b).apply(s); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/optics/functions/Under.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/Under.java new file mode 100644 index 000000000..81b915867 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/Under.java @@ -0,0 +1,60 @@ +package com.jnape.palatable.lambda.optics.functions; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functions.Fn3; +import com.jnape.palatable.lambda.functor.builtin.Exchange; +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.optics.Iso; +import com.jnape.palatable.lambda.optics.Optic; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; + +/** + * The inverse of {@link Over}: given an {@link Iso}, a function from T to S, and a "smaller" + * value B, return a "smaller" value A by traversing around the type ring (B -> T + * -> S -> A). + * + * @param the larger type for focusing + * @param the larger type for mirrored focusing + * @param the smaller type for focusing + * @param the smaller type for mirrored focusing + */ +public final class Under implements + Fn3, ? super Identity, S, T, A, B>, + Fn1, B, A> { + + private static final Under INSTANCE = new Under<>(); + + private Under() { + } + + @Override + public A checkedApply(Optic, ? super Identity, S, T, A, B> optic, + Fn1 fn, + B b) { + Exchange> exchange = optic.apply(new Exchange<>(id(), Identity::new)); + return exchange.sa().apply(fn.apply(exchange.bt().apply(b).runIdentity())); + } + + @SuppressWarnings("unchecked") + public static Under under() { + return (Under) INSTANCE; + } + + public static Fn2, B, A> under( + Optic, ? super Identity, S, T, A, B> optic) { + return Under.under().apply(optic); + } + + public static Fn1 under( + Optic, ? super Identity, S, T, A, B> optic, + Fn1 fn) { + return under(optic).apply(fn); + } + + public static A under(Optic, ? super Identity, S, T, A, B> optic, + Fn1 fn, B b) { + return under(optic, fn).apply(b); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/optics/functions/View.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/View.java new file mode 100644 index 000000000..c63074ac2 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/View.java @@ -0,0 +1,47 @@ +package com.jnape.palatable.lambda.optics.functions; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functor.builtin.Const; +import com.jnape.palatable.lambda.optics.Optic; + +/** + * Given an {@link Optic} and a "larger" value S, retrieve a "smaller" value A by lifting the + * {@link Optic} into the {@link Const} functor. + *

+ * More idiomatically, this function can be used to treat a {@link Optic} as a "getter" of As from + * Ss. + * + * @param the type of the larger value + * @param the type of the larger updated value (unused, but necessary for composition) + * @param the type of the smaller retrieving value + * @param the type of the smaller setting value (unused, but necessary for composition) + * @see Set + * @see Over + */ +public final class View implements Fn2, ? super Const, S, T, A, B>, S, A> { + + private static final View INSTANCE = new View<>(); + + private View() { + } + + @Override + public A checkedApply(Optic, ? super Const, S, T, A, B> optic, S s) { + return optic., Const, Const, Const, Fn1>, Fn1>>apply( + Const::new).apply(s).runConst(); + } + + @SuppressWarnings("unchecked") + public static View view() { + return (View) INSTANCE; + } + + public static Fn1 view(Optic, ? super Const, S, T, A, B> optic) { + return View.view().apply(optic); + } + + public static A view(Optic, ? super Const, S, T, A, B> optic, S s) { + return view(optic).apply(s); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/CollectionLens.java b/src/main/java/com/jnape/palatable/lambda/optics/lenses/CollectionLens.java similarity index 82% rename from src/main/java/com/jnape/palatable/lambda/lens/lenses/CollectionLens.java rename to src/main/java/com/jnape/palatable/lambda/optics/lenses/CollectionLens.java index b43c0e596..18ccd9faa 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/lenses/CollectionLens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/lenses/CollectionLens.java @@ -1,14 +1,14 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.optics.Lens; import java.util.Collection; import java.util.HashSet; import java.util.Set; -import java.util.function.Function; import java.util.stream.Stream; -import static com.jnape.palatable.lambda.lens.Lens.simpleLens; +import static com.jnape.palatable.lambda.optics.Lens.simpleLens; /** * Lenses that operate on {@link Collection}s. @@ -27,7 +27,7 @@ private CollectionLens() { * @param the type of the collection * @return a lens that focuses on a copy of CX */ - public static > Lens.Simple asCopy(Function copyFn) { + public static > Lens.Simple asCopy(Fn1 copyFn) { return simpleLens(copyFn, (__, copy) -> copy); } @@ -40,8 +40,7 @@ public static > Lens.Simple asCopy(Function< * @param the type of the collection * @return a lens that focuses on a Collection as a Set */ - public static > Lens.Simple> asSet( - Function copyFn) { + public static > Lens.Simple> asSet(Fn1 copyFn) { return simpleLens(HashSet::new, (xsL, xsS) -> { Set missing = new HashSet<>(xsS); missing.removeAll(xsL); @@ -63,9 +62,10 @@ public static > Lens.Simple> asSet( * @param the type of the collection * @return a lens that focuses on a Collection as a stream. */ + @SuppressWarnings("RedundantTypeArguments") public static > Lens.Simple> asStream( - Function copyFn) { - return simpleLens(Collection::stream, (xsL, xsS) -> { + Fn1 copyFn) { + return simpleLens(Collection::stream, (xsL, xsS) -> { CX updated = copyFn.apply(xsL); updated.clear(); xsS.forEach(updated::add); diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/EitherLens.java b/src/main/java/com/jnape/palatable/lambda/optics/lenses/EitherLens.java similarity index 83% rename from src/main/java/com/jnape/palatable/lambda/lens/lenses/EitherLens.java rename to src/main/java/com/jnape/palatable/lambda/optics/lenses/EitherLens.java index 50b840e5c..8463d0eb1 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/lenses/EitherLens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/lenses/EitherLens.java @@ -1,14 +1,14 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; import com.jnape.palatable.lambda.adt.Either; import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Lens; -import static com.jnape.palatable.lambda.lens.Lens.simpleLens; +import static com.jnape.palatable.lambda.optics.Lens.simpleLens; /** - * Lenses that operate on {@link Either}s. + * Lenses for {@link Either}. */ public final class EitherLens { @@ -26,7 +26,7 @@ private EitherLens() { * @param the right parameter type * @return a lens that focuses on right values */ - public static Lens.Simple, Maybe> right() { + public static Lens.Simple, Maybe> _right() { return simpleLens(CoProduct2::projectB, (lOrR, maybeR) -> maybeR.>fmap(Either::right).orElse(lOrR)); } @@ -41,7 +41,7 @@ public static Lens.Simple, Maybe> right() { * @param the right parameter type * @return a lens that focuses on left values */ - public static Lens.Simple, Maybe> left() { + public static Lens.Simple, Maybe> _left() { return simpleLens(CoProduct2::projectA, (lOrR, maybeL) -> maybeL.>fmap(Either::left).orElse(lOrR)); } } diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/HListLens.java b/src/main/java/com/jnape/palatable/lambda/optics/lenses/HListLens.java similarity index 90% rename from src/main/java/com/jnape/palatable/lambda/lens/lenses/HListLens.java rename to src/main/java/com/jnape/palatable/lambda/optics/lenses/HListLens.java index bc0ce452b..2af87a94a 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/lenses/HListLens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/lenses/HListLens.java @@ -1,12 +1,12 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.HList.HCons; import com.jnape.palatable.lambda.adt.hlist.Index; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Lens; import static com.jnape.palatable.lambda.adt.hlist.HList.cons; -import static com.jnape.palatable.lambda.lens.Lens.simpleLens; +import static com.jnape.palatable.lambda.optics.Lens.simpleLens; /** * Lenses that operate on {@link HList}s. diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/HMapLens.java b/src/main/java/com/jnape/palatable/lambda/optics/lenses/HMapLens.java similarity index 81% rename from src/main/java/com/jnape/palatable/lambda/lens/lenses/HMapLens.java rename to src/main/java/com/jnape/palatable/lambda/optics/lenses/HMapLens.java index c7fd953da..f98446254 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/lenses/HMapLens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/lenses/HMapLens.java @@ -1,11 +1,11 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.hmap.HMap; import com.jnape.palatable.lambda.adt.hmap.TypeSafeKey; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Lens; -import static com.jnape.palatable.lambda.lens.Lens.simpleLens; +import static com.jnape.palatable.lambda.optics.Lens.simpleLens; /** * Lenses that operate on {@link HMap}s. diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/IterableLens.java b/src/main/java/com/jnape/palatable/lambda/optics/lenses/IterableLens.java similarity index 79% rename from src/main/java/com/jnape/palatable/lambda/lens/lenses/IterableLens.java rename to src/main/java/com/jnape/palatable/lambda/optics/lenses/IterableLens.java index cccf68730..b0f125c14 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/lenses/IterableLens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/lenses/IterableLens.java @@ -1,18 +1,18 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.functions.builtin.fn1.Head; import com.jnape.palatable.lambda.functions.builtin.fn1.Tail; -import com.jnape.palatable.lambda.lens.Iso; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Iso; +import com.jnape.palatable.lambda.optics.Lens; -import static com.jnape.palatable.lambda.functions.Fn2.fn2; +import static com.jnape.palatable.lambda.functions.Fn2.curried; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.functions.builtin.fn2.Cons.cons; import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; -import static com.jnape.palatable.lambda.lens.Iso.simpleIso; -import static com.jnape.palatable.lambda.lens.Lens.simpleLens; -import static com.jnape.palatable.lambda.lens.functions.View.view; +import static com.jnape.palatable.lambda.optics.Iso.simpleIso; +import static com.jnape.palatable.lambda.optics.Lens.simpleLens; +import static com.jnape.palatable.lambda.optics.functions.View.view; /** * Lenses that operate on {@link Iterable}s. @@ -45,7 +45,7 @@ public static Lens.Simple, Maybe> head() { * @return a lens focusing on the tail of an {@link Iterable} */ public static Lens.Simple, Iterable> tail() { - return simpleLens(Tail::tail, fn2(Head.head().andThen(o -> o.fmap(cons()).orElse(id()))).toBiFunction()); + return simpleLens(Tail::tail, curried(Head.head().fmap(o -> o.fmap(cons()).orElse(id())))); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/ListLens.java b/src/main/java/com/jnape/palatable/lambda/optics/lenses/ListLens.java similarity index 88% rename from src/main/java/com/jnape/palatable/lambda/lens/lenses/ListLens.java rename to src/main/java/com/jnape/palatable/lambda/optics/lenses/ListLens.java index b7857df2a..383c1a226 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/lenses/ListLens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/lenses/ListLens.java @@ -1,7 +1,7 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; import com.jnape.palatable.lambda.adt.Maybe; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Lens; import java.util.ArrayList; import java.util.List; @@ -9,9 +9,9 @@ import static com.jnape.palatable.lambda.adt.Maybe.maybe; import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat; import static com.jnape.palatable.lambda.functions.builtin.fn2.Take.take; -import static com.jnape.palatable.lambda.lens.Lens.simpleLens; -import static com.jnape.palatable.lambda.lens.lenses.MaybeLens.unLiftA; -import static com.jnape.palatable.lambda.lens.lenses.MaybeLens.unLiftB; +import static com.jnape.palatable.lambda.optics.Lens.simpleLens; +import static com.jnape.palatable.lambda.optics.lenses.MaybeLens.unLiftA; +import static com.jnape.palatable.lambda.optics.lenses.MaybeLens.unLiftB; import static java.lang.Math.abs; /** @@ -73,8 +73,7 @@ public static Lens.Simple, Maybe> elementAt(int index) { * @param the list element type * @return the element at the index, or defaultValue */ - @SuppressWarnings("unchecked") public static Lens.Simple, X> elementAt(int index, X defaultValue) { - return unLiftB(unLiftA(elementAt(index), defaultValue))::apply; + return Lens.Simple.adapt(unLiftB(unLiftA(elementAt(index), defaultValue))); } } diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java b/src/main/java/com/jnape/palatable/lambda/optics/lenses/MapLens.java similarity index 82% rename from src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java rename to src/main/java/com/jnape/palatable/lambda/optics/lenses/MapLens.java index e6df4f236..729ca0b23 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/lenses/MapLens.java @@ -1,12 +1,12 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.IO; import com.jnape.palatable.lambda.functions.builtin.fn2.Filter; -import com.jnape.palatable.lambda.lens.Iso; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.io.IO; +import com.jnape.palatable.lambda.optics.Iso; +import com.jnape.palatable.lambda.optics.Lens; import java.util.ArrayList; import java.util.Collection; @@ -14,19 +14,21 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -import java.util.function.Function; import static com.jnape.palatable.lambda.adt.Maybe.maybe; +import static com.jnape.palatable.lambda.functions.Effect.effect; import static com.jnape.palatable.lambda.functions.builtin.fn2.Alter.alter; import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; import static com.jnape.palatable.lambda.functions.builtin.fn2.ToCollection.toCollection; import static com.jnape.palatable.lambda.functions.builtin.fn2.ToMap.toMap; -import static com.jnape.palatable.lambda.lens.Lens.Simple.adapt; -import static com.jnape.palatable.lambda.lens.Lens.lens; -import static com.jnape.palatable.lambda.lens.Lens.simpleLens; -import static com.jnape.palatable.lambda.lens.functions.View.view; -import static com.jnape.palatable.lambda.lens.lenses.MaybeLens.unLiftA; -import static com.jnape.palatable.lambda.lens.lenses.MaybeLens.unLiftB; +import static com.jnape.palatable.lambda.functions.specialized.SideEffect.sideEffect; +import static com.jnape.palatable.lambda.io.IO.io; +import static com.jnape.palatable.lambda.optics.Lens.Simple.adapt; +import static com.jnape.palatable.lambda.optics.Lens.lens; +import static com.jnape.palatable.lambda.optics.Lens.simpleLens; +import static com.jnape.palatable.lambda.optics.functions.View.view; +import static com.jnape.palatable.lambda.optics.lenses.MaybeLens.unLiftA; +import static com.jnape.palatable.lambda.optics.lenses.MaybeLens.unLiftB; /** * Lenses that operate on {@link Map}s. @@ -47,7 +49,7 @@ private MapLens() { * @return a lens that focuses on copies of maps as a specific subtype */ public static , K, V> Lens, M, M, M> asCopy( - Function, ? extends M> copyFn) { + Fn1, ? extends M> copyFn) { return lens(copyFn, (__, copy) -> copy); } @@ -66,18 +68,18 @@ public static Lens.Simple, Map> asCopy() { * A lens that focuses on a value at a key in a map, as a {@link Maybe}, and produces a subtype M on * the way back out. * + * @param copyFn the copy function + * @param k the key to focus on * @param the map subtype * @param the key type * @param the value type - * @param k the key to focus on - * @param copyFn the copy function * @return a lens that focuses on the value at key, as a {@link Maybe} */ public static , K, V> Lens, M, Maybe, Maybe> valueAt( - Function, ? extends M> copyFn, K k) { + Fn1, ? extends M> copyFn, K k) { return lens(m -> maybe(m.get(k)), (m, maybeV) -> maybeV - .>>fmap(v -> alter(updated -> updated.put(k, v))) - .orElse(alter(updated -> updated.remove(k))) + .>>fmap(v -> alter(effect(updated -> io(() -> updated.put(k, v))))) + .orElse(alter(updated -> io(sideEffect(() -> updated.remove(k))))) .apply(copyFn.apply(m)) .unsafePerformIO()); } @@ -119,9 +121,9 @@ public static Lens.Simple, V> valueAt(K k, V defaultValue) { */ public static Lens.Simple, Set> keys() { return simpleLens(m -> new HashSet<>(m.keySet()), (m, ks) -> { - HashSet ksCopy = new HashSet<>(ks); - Map updated = new HashMap<>(m); - Set keys = updated.keySet(); + HashSet ksCopy = new HashSet<>(ks); + Map updated = new HashMap<>(m); + Set keys = updated.keySet(); keys.retainAll(ksCopy); ksCopy.removeAll(keys); ksCopy.forEach(k -> updated.put(k, null)); @@ -142,11 +144,11 @@ public static Lens.Simple, Set> keys() { */ public static Lens.Simple, Collection> values() { return simpleLens(m -> new ArrayList<>(m.values()), (m, vs) -> { - Map updated = new HashMap<>(m); - Set valueSet = new HashSet<>(vs); + Map updated = new HashMap<>(m); + Set valueSet = new HashSet<>(vs); Set matchingKeys = Filter.>filter(kv -> valueSet.contains(kv.getValue())) - .andThen(map(Map.Entry::getKey)) - .andThen(toCollection(HashSet::new)) + .fmap(map(Map.Entry::getKey)) + .fmap(toCollection(HashSet::new)) .apply(updated.entrySet()); updated.keySet().retainAll(matchingKeys); return updated; diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/MaybeLens.java b/src/main/java/com/jnape/palatable/lambda/optics/lenses/MaybeLens.java similarity index 97% rename from src/main/java/com/jnape/palatable/lambda/lens/lenses/MaybeLens.java rename to src/main/java/com/jnape/palatable/lambda/optics/lenses/MaybeLens.java index 0917b07ae..5bb9f93da 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/lenses/MaybeLens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/lenses/MaybeLens.java @@ -1,9 +1,9 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; import com.jnape.palatable.lambda.adt.Maybe; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Lens; -import static com.jnape.palatable.lambda.lens.Lens.simpleLens; +import static com.jnape.palatable.lambda.optics.Lens.simpleLens; /** * Lenses that operate on {@link Maybe}. diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/SetLens.java b/src/main/java/com/jnape/palatable/lambda/optics/lenses/SetLens.java similarity index 73% rename from src/main/java/com/jnape/palatable/lambda/lens/lenses/SetLens.java rename to src/main/java/com/jnape/palatable/lambda/optics/lenses/SetLens.java index b48ceea24..75c7ab756 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/lenses/SetLens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/lenses/SetLens.java @@ -1,12 +1,12 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.optics.Lens; import java.util.HashSet; import java.util.Set; -import java.util.function.Function; -import static com.jnape.palatable.lambda.lens.Lens.simpleLens; +import static com.jnape.palatable.lambda.optics.Lens.simpleLens; /** * Lenses that operate on {@link Set}s. @@ -26,8 +26,8 @@ private SetLens() { * @param the set to focus on * @return a lens that focuses on a value's inclusion in a given {@link Set} */ - public static > Lens.Simple contains( - Function copyFn, A a) { + public static > Lens.Simple contains(Fn1 copyFn, + A a) { return simpleLens(setA -> setA.contains(a), (setA, include) -> { SetA copy = copyFn.apply(setA); @@ -38,8 +38,8 @@ public static > Lens.Simple contains( } /** - * A lens that focuses on whether a {@link Set} contains some value a. Like {@link #contains(Function, - * Object)} but with an implicit copy function that produces {@link HashSet}s. + * A lens that focuses on whether a {@link Set} contains some value a. Like + * {@link #contains(Fn1, Object)} but with an implicit copy function that produces {@link HashSet}s. * * @param a the value in question * @param the value type diff --git a/src/main/java/com/jnape/palatable/lambda/optics/prisms/EitherPrism.java b/src/main/java/com/jnape/palatable/lambda/optics/prisms/EitherPrism.java new file mode 100644 index 000000000..462f30b0a --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/optics/prisms/EitherPrism.java @@ -0,0 +1,38 @@ +package com.jnape.palatable.lambda.optics.prisms; + +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; +import com.jnape.palatable.lambda.optics.Prism; + +import static com.jnape.palatable.lambda.optics.Prism.simplePrism; + +/** + * {@link Prism Prisms} for {@link Either}. + */ +public final class EitherPrism { + + private EitherPrism() { + } + + /** + * A {@link Prism} that focuses on the {@link Either#left(Object) left} value of an {@link Either}. + * + * @param the left type + * @param the right type + * @return the {@link Prism} + */ + public static Prism.Simple, L> _left() { + return simplePrism(CoProduct2::projectA, Either::left); + } + + /** + * A {@link Prism} that focuses on the {@link Either#right(Object) right} value of an {@link Either}. + * + * @param the left type + * @param the right type + * @return the {@link Prism} + */ + public static Prism.Simple, R> _right() { + return simplePrism(CoProduct2::projectB, Either::right); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/optics/prisms/MapPrism.java b/src/main/java/com/jnape/palatable/lambda/optics/prisms/MapPrism.java new file mode 100644 index 000000000..2d1ee7930 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/optics/prisms/MapPrism.java @@ -0,0 +1,49 @@ +package com.jnape.palatable.lambda.optics.prisms; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.optics.Prism; + +import java.util.HashMap; +import java.util.Map; + +import static com.jnape.palatable.lambda.adt.Maybe.maybe; +import static com.jnape.palatable.lambda.optics.Prism.Simple.adapt; +import static com.jnape.palatable.lambda.optics.Prism.prism; +import static java.util.Collections.singletonMap; + +/** + * {@link Prism Prisms} for {@link Map Maps}. + */ +public final class MapPrism { + private MapPrism() { + } + + /** + * A {@link Prism} that focuses on the value at a key in a {@link Map}, and produces an instance of M + * on the way back out. + * + * @param copyFn the copy function + * @param k the key to focus on + * @param the {@link Map} subtype + * @param the key type + * @param the value type + * @return the {@link Prism} + */ + public static , K, V> Prism, M, V, V> valueAt(Fn1, M> copyFn, K k) { + return prism(m -> maybe(m.get(k)).toEither(copyFn.thunk(m)), + v -> copyFn.apply(singletonMap(k, v))); + } + + /** + * A {@link Prism} that focuses on the value at a key in a {@link Map} making no guarantees about the {@link Map} + * interface. + * + * @param k the key to focus on + * @param the key type + * @param the value type + * @return the {@link Prism} + */ + public static Prism.Simple, V> valueAt(K k) { + return adapt(valueAt(HashMap::new, k)); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/optics/prisms/MaybePrism.java b/src/main/java/com/jnape/palatable/lambda/optics/prisms/MaybePrism.java new file mode 100644 index 000000000..eaf5ed0f1 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/optics/prisms/MaybePrism.java @@ -0,0 +1,41 @@ +package com.jnape.palatable.lambda.optics.prisms; + +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; +import com.jnape.palatable.lambda.optics.Prism; + +import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.optics.Prism.prism; +import static com.jnape.palatable.lambda.optics.Prism.simplePrism; + +/** + * {@link Prism Prisms} for {@link Maybe}. + */ +public final class MaybePrism { + + private MaybePrism() { + } + + /** + * A {@link Prism} that focuses on present values in a {@link Maybe}. + * + * @param {@link Maybe} the input value + * @param {@link Maybe} the output value + * @return the {@link Prism} + */ + public static Prism, Maybe, A, B> _just() { + return prism(maybeA -> maybeA.toEither(Maybe::nothing), Maybe::just); + } + + /** + * A {@link Prism} that focuses on absent values in a {@link Maybe}, for symmetry. + * + * @param {@link Maybe} the input and output value + * @return the {@link Prism} + */ + public static Prism.Simple, Unit> _nothing() { + return simplePrism(CoProduct2::projectA, constantly(nothing())); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/optics/prisms/UUIDPrism.java b/src/main/java/com/jnape/palatable/lambda/optics/prisms/UUIDPrism.java new file mode 100644 index 000000000..c9a70080e --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/optics/prisms/UUIDPrism.java @@ -0,0 +1,22 @@ +package com.jnape.palatable.lambda.optics.prisms; + +import com.jnape.palatable.lambda.optics.Prism; + +import java.util.UUID; + +/** + * {@link Prism Prisms} for {@link UUID}. + */ +public final class UUIDPrism { + private UUIDPrism() { + } + + /** + * A {@link Prism} that focuses on a {@link String} as a {@link UUID}. + * + * @return the {@link Prism} + */ + public static Prism.Simple uuid() { + return Prism.fromPartial(UUID::fromString, UUID::toString); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/Semigroup.java b/src/main/java/com/jnape/palatable/lambda/semigroup/Semigroup.java index b82aea644..a061328ce 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/Semigroup.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/Semigroup.java @@ -3,6 +3,9 @@ import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft; import com.jnape.palatable.lambda.functions.builtin.fn3.FoldRight; +import com.jnape.palatable.lambda.functor.builtin.Lazy; + +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** * A Semigroup is a closed, associative category. As closure can be implied by the type signature, and @@ -23,7 +26,7 @@ public interface Semigroup extends Fn2 { * @see FoldLeft */ default A foldLeft(A a, Iterable as) { - return FoldLeft.foldLeft(toBiFunction(), a, as); + return FoldLeft.foldLeft(this, a, as); } /** @@ -35,8 +38,8 @@ default A foldLeft(A a, Iterable as) { * @return the folded result * @see FoldRight */ - default A foldRight(A a, Iterable as) { - return FoldRight.foldRight(toBiFunction(), a, as); + default Lazy foldRight(A a, Iterable as) { + return FoldRight.foldRight((y, lazyX) -> lazyX.fmap(x -> apply(x, y)), lazy(a), as); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java index 9c5392860..f39fd05cd 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java @@ -25,19 +25,19 @@ */ public final class Absent implements SemigroupFactory, Maybe> { - private static final Absent INSTANCE = new Absent<>(); + private static final Absent INSTANCE = new Absent<>(); private Absent() { } @Override - public Semigroup> apply(Semigroup aSemigroup) { - return LiftA2., Maybe, Maybe>liftA2(aSemigroup.toBiFunction())::apply; + public Semigroup> checkedApply(Semigroup aSemigroup) { + return LiftA2., Maybe, Maybe, Maybe>liftA2(aSemigroup)::apply; } @SuppressWarnings("unchecked") public static Absent absent() { - return INSTANCE; + return (Absent) INSTANCE; } public static Semigroup> absent(Semigroup semigroup) { diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Collapse.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Collapse.java index 9c2046632..7b163898d 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Collapse.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Collapse.java @@ -21,20 +21,20 @@ */ public final class Collapse<_1, _2> implements BiSemigroupFactory, Semigroup<_2>, Tuple2<_1, _2>> { - private static final Collapse INSTANCE = new Collapse(); + private static final Collapse INSTANCE = new Collapse<>(); private Collapse() { } @Override - public Semigroup> apply(Semigroup<_1> _1Semigroup, Semigroup<_2> _2Semigroup) { + public Semigroup> checkedApply(Semigroup<_1> _1Semigroup, Semigroup<_2> _2Semigroup) { return (x, y) -> x.biMap(_1Semigroup.flip().apply(y._1()), _2Semigroup.flip().apply(y._2())); } @SuppressWarnings("unchecked") public static <_1, _2> Collapse<_1, _2> collapse() { - return INSTANCE; + return (Collapse<_1, _2>) INSTANCE; } public static <_1, _2> SemigroupFactory, Tuple2<_1, _2>> collapse(Semigroup<_1> _1Semigroup) { diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Compose.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Compose.java index 9857ab413..cba9a218f 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Compose.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Compose.java @@ -20,19 +20,19 @@ */ public final class Compose implements SemigroupFactory, CompletableFuture> { - private static final Compose INSTANCE = new Compose(); + private static final Compose INSTANCE = new Compose<>(); private Compose() { } @Override - public Semigroup> apply(Semigroup aSemigroup) { + public Semigroup> checkedApply(Semigroup aSemigroup) { return (futureX, futureY) -> futureX.thenCompose(x -> futureY.thenApply(y -> aSemigroup.apply(x, y))); } @SuppressWarnings("unchecked") public static Compose compose() { - return INSTANCE; + return (Compose) INSTANCE; } public static Semigroup> compose(Semigroup aSemigroup) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersection.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Intersection.java similarity index 78% rename from src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersection.java rename to src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Intersection.java index 178b7be8c..cf33e9b3a 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersection.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Intersection.java @@ -1,8 +1,8 @@ -package com.jnape.palatable.lambda.functions.builtin.fn2; +package com.jnape.palatable.lambda.semigroup.builtin; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.builtin.fn1.Distinct; +import com.jnape.palatable.lambda.semigroup.Semigroup; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Distinct.distinct; @@ -16,21 +16,21 @@ * * @param the {@link Iterable} element type */ -public final class Intersection implements Fn2, Iterable, Iterable> { +public final class Intersection implements Semigroup> { - private static final Intersection INSTANCE = new Intersection(); + private static final Intersection INSTANCE = new Intersection<>(); private Intersection() { } @Override - public Iterable apply(Iterable xs, Iterable ys) { + public Iterable checkedApply(Iterable xs, Iterable ys) { return filter(x -> find(eq(x), ys).fmap(constantly(true)).orElse(false), distinct(xs)); } @SuppressWarnings("unchecked") public static Intersection intersection() { - return INSTANCE; + return (Intersection) INSTANCE; } public static Fn1, Iterable> intersection(Iterable xs) { diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAll.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAll.java index b8955b2e0..e5ac2caf1 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAll.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAll.java @@ -30,19 +30,19 @@ */ public final class LeftAll implements SemigroupFactory, Either> { - private static final LeftAll INSTANCE = new LeftAll(); + private static final LeftAll INSTANCE = new LeftAll<>(); private LeftAll() { } @Override - public Semigroup> apply(Semigroup lSemigroup) { + public Semigroup> checkedApply(Semigroup lSemigroup) { return (x, y) -> x.match(xL -> y.match(yL -> left(lSemigroup.apply(xL, yL)), Either::right), Either::right); } @SuppressWarnings("unchecked") public static LeftAll leftAll() { - return INSTANCE; + return (LeftAll) INSTANCE; } public static Semigroup> leftAll(Semigroup lSemigroup) { diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAny.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAny.java index b93133143..91a892dfb 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAny.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAny.java @@ -29,13 +29,13 @@ */ public final class LeftAny implements SemigroupFactory, Either> { - private static final LeftAny INSTANCE = new LeftAny(); + private static final LeftAny INSTANCE = new LeftAny<>(); private LeftAny() { } @Override - public Semigroup> apply(Semigroup lSemigroup) { + public Semigroup> checkedApply(Semigroup lSemigroup) { return (x, y) -> x.match(xL -> y.match(yL -> left(lSemigroup.apply(xL, yL)), yR -> left(xL)), xR -> y); @@ -43,7 +43,7 @@ public Semigroup> apply(Semigroup lSemigroup) { @SuppressWarnings("unchecked") public static LeftAny leftAny() { - return INSTANCE; + return (LeftAny) INSTANCE; } public static Semigroup> leftAny(Semigroup lSemigroup) { diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Max.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Max.java index 3687a5187..a9cc3db66 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Max.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Max.java @@ -20,19 +20,19 @@ */ public final class Max> implements Semigroup { - private static final Max INSTANCE = new Max(); + private static final Max INSTANCE = new Max<>(); private Max() { } @Override - public A apply(A x, A y) { + public A checkedApply(A x, A y) { return maxBy(id(), x, y); } @SuppressWarnings("unchecked") public static > Max max() { - return INSTANCE; + return (Max) INSTANCE; } public static > Fn1 max(A x) { diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxBy.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxBy.java index 5e6cbbe5c..78d361ba8 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxBy.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxBy.java @@ -4,8 +4,6 @@ import com.jnape.palatable.lambda.functions.specialized.SemigroupFactory; import com.jnape.palatable.lambda.semigroup.Semigroup; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn3.LTBy.ltBy; /** @@ -22,33 +20,32 @@ * @see Max * @see MinBy */ -public final class MaxBy> implements SemigroupFactory, A> { +public final class MaxBy> implements SemigroupFactory, A> { - private static final MaxBy INSTANCE = new MaxBy(); + private static final MaxBy INSTANCE = new MaxBy<>(); private MaxBy() { } @Override - public Semigroup apply(Function compareFn) { + public Semigroup checkedApply(Fn1 compareFn) { return (x, y) -> ltBy(compareFn, y, x) ? y : x; } @SuppressWarnings("unchecked") public static > MaxBy maxBy() { - return INSTANCE; + return (MaxBy) INSTANCE; } - public static > Semigroup maxBy( - Function compareFn) { + public static > Semigroup maxBy(Fn1 compareFn) { return MaxBy.maxBy().apply(compareFn); } - public static > Fn1 maxBy(Function compareFn, A x) { + public static > Fn1 maxBy(Fn1 compareFn, A x) { return MaxBy.maxBy(compareFn).apply(x); } - public static > A maxBy(Function compareFn, A x, A y) { + public static > A maxBy(Fn1 compareFn, A x, A y) { return maxBy(compareFn, x).apply(y); } } diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Merge.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Merge.java index 75bd81ffd..833e1aa57 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Merge.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Merge.java @@ -20,19 +20,19 @@ */ public final class Merge implements BiSemigroupFactory, Semigroup, Either> { - private static final Merge INSTANCE = new Merge(); + private static final Merge INSTANCE = new Merge<>(); private Merge() { } @Override - public Semigroup> apply(Semigroup lSemigroup, Semigroup rSemigroup) { + public Semigroup> checkedApply(Semigroup lSemigroup, Semigroup rSemigroup) { return (x, y) -> x.merge(lSemigroup::apply, rSemigroup::apply, y); } @SuppressWarnings("unchecked") public static Merge merge() { - return INSTANCE; + return (Merge) INSTANCE; } public static SemigroupFactory, Either> merge(Semigroup lSemigroup) { diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Min.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Min.java index 742055ed5..747bd5d25 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Min.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Min.java @@ -20,19 +20,19 @@ */ public final class Min> implements Semigroup { - private static final Min INSTANCE = new Min(); + private static final Min INSTANCE = new Min<>(); private Min() { } @Override - public A apply(A x, A y) { + public A checkedApply(A x, A y) { return minBy(id(), x, y); } @SuppressWarnings("unchecked") public static > Min min() { - return INSTANCE; + return (Min) INSTANCE; } public static > Fn1 min(A x) { diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MinBy.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MinBy.java index 3a7ea9a71..07ee12999 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MinBy.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MinBy.java @@ -4,8 +4,6 @@ import com.jnape.palatable.lambda.functions.specialized.SemigroupFactory; import com.jnape.palatable.lambda.semigroup.Semigroup; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn3.GTBy.gtBy; /** @@ -22,33 +20,32 @@ * @see Min * @see MaxBy */ -public final class MinBy> implements SemigroupFactory, A> { +public final class MinBy> implements SemigroupFactory, A> { - private static final MinBy INSTANCE = new MinBy(); + private static final MinBy INSTANCE = new MinBy<>(); private MinBy() { } @Override - public Semigroup apply(Function compareFn) { + public Semigroup checkedApply(Fn1 compareFn) { return (x, y) -> gtBy(compareFn, y, x) ? y : x; } @SuppressWarnings("unchecked") public static > MinBy minBy() { - return INSTANCE; + return (MinBy) INSTANCE; } - public static > Semigroup minBy( - Function compareFn) { + public static > Semigroup minBy(Fn1 compareFn) { return MinBy.minBy().apply(compareFn); } - public static > Fn1 minBy(Function compareFn, A x) { + public static > Fn1 minBy(Fn1 compareFn, A x) { return MinBy.minBy(compareFn).apply(x); } - public static > A minBy(Function compareFn, A x, A y) { + public static > A minBy(Fn1 compareFn, A x, A y) { return minBy(compareFn, x).apply(y); } } diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAll.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAll.java index 7f1bdab5b..5bb6fa018 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAll.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAll.java @@ -29,19 +29,19 @@ */ public final class RightAll implements SemigroupFactory, Either> { - private static final RightAll INSTANCE = new RightAll(); + private static final RightAll INSTANCE = new RightAll<>(); private RightAll() { } @Override - public Semigroup> apply(Semigroup rSemigroup) { + public Semigroup> checkedApply(Semigroup rSemigroup) { return (eitherX, eitherY) -> eitherX.flatMap(xR -> eitherY.flatMap(yR -> right(rSemigroup.apply(xR, yR)))); } @SuppressWarnings("unchecked") public static RightAll rightAll() { - return INSTANCE; + return (RightAll) INSTANCE; } public static Semigroup> rightAll(Semigroup rSemigroup) { diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAny.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAny.java index 00f528054..8dcc439a3 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAny.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAny.java @@ -30,21 +30,21 @@ */ public final class RightAny implements SemigroupFactory, Either> { - private static final RightAny INSTANCE = new RightAny(); + private static final RightAny INSTANCE = new RightAny<>(); private RightAny() { } @Override - public Semigroup> apply(Semigroup rSemigroup) { + public Semigroup> checkedApply(Semigroup rSemigroup) { return (x, y) -> x.match(constantly(y), xR -> y.match(constantly(right(xR)), - rSemigroup.apply(xR).andThen(Either::right))); + rSemigroup.apply(xR).fmap(Either::right))); } @SuppressWarnings("unchecked") public static RightAny rightAny() { - return INSTANCE; + return (RightAny) INSTANCE; } public static Semigroup> rightAny(Semigroup rSemigroup) { diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RunAll.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RunAll.java index 5ae09b8ac..f84d0243a 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RunAll.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RunAll.java @@ -1,8 +1,8 @@ package com.jnape.palatable.lambda.semigroup.builtin; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.IO; import com.jnape.palatable.lambda.functions.specialized.SemigroupFactory; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.semigroup.Semigroup; /** @@ -13,19 +13,19 @@ */ public final class RunAll implements SemigroupFactory, IO> { - private static final RunAll INSTANCE = new RunAll(); + private static final RunAll INSTANCE = new RunAll<>(); private RunAll() { } @Override - public Semigroup> apply(Semigroup semigroup) { + public Semigroup> checkedApply(Semigroup semigroup) { return (ioX, ioY) -> ioY.zip(ioX.fmap(semigroup)); } @SuppressWarnings("unchecked") public static RunAll runAll() { - return INSTANCE; + return (RunAll) INSTANCE; } public static Semigroup> runAll(Semigroup semigroup) { diff --git a/src/main/java/com/jnape/palatable/lambda/traversable/LambdaIterable.java b/src/main/java/com/jnape/palatable/lambda/traversable/LambdaIterable.java index 8a40c9cb5..6fe5f4a38 100644 --- a/src/main/java/com/jnape/palatable/lambda/traversable/LambdaIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/traversable/LambdaIterable.java @@ -1,16 +1,19 @@ package com.jnape.palatable.lambda.traversable; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.builtin.fn1.Empty; +import com.jnape.palatable.lambda.functions.builtin.fn3.FoldRight; import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import java.util.Iterator; import java.util.Objects; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn1.Flatten.flatten; import static com.jnape.palatable.lambda.functions.builtin.fn2.Cons.cons; import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; -import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldRight.foldRight; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static java.util.Collections.emptyList; import static java.util.Collections.singleton; @@ -20,7 +23,7 @@ * @param the {@link Iterable} element type * @see LambdaMap */ -public final class LambdaIterable implements Monad, Traversable { +public final class LambdaIterable implements Monad>, Traversable> { private final Iterable as; @SuppressWarnings("unchecked") @@ -37,11 +40,17 @@ public Iterable unwrap() { return as; } + /** + * {@inheritDoc} + */ @Override - public LambdaIterable fmap(Function fn) { + public LambdaIterable fmap(Fn1 fn) { return wrap(map(fn, as)); } + /** + * {@inheritDoc} + */ @Override public LambdaIterable pure(B b) { return wrap(singleton(b)); @@ -58,40 +67,68 @@ public LambdaIterable pure(B b) { * @return the zipped LambdaIterable */ @Override - public LambdaIterable zip(Applicative, LambdaIterable> appFn) { + public LambdaIterable zip(Applicative, LambdaIterable> appFn) { return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, LambdaIterable>> lazyAppFn) { + return Empty.empty(as) + ? lazy(LambdaIterable.empty()) + : Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); + } + + /** + * {@inheritDoc} + */ @Override - public LambdaIterable discardL(Applicative appB) { + public LambdaIterable discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override - public LambdaIterable discardR(Applicative appB) { + public LambdaIterable discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override - public LambdaIterable flatMap(Function> f) { + public LambdaIterable flatMap(Fn1>> f) { return wrap(flatten(map(a -> f.apply(a).>coerce().unwrap(), as))); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") - public , AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, - Function pure) { - return foldRight((a, appTrav) -> (AppTrav) appTrav.zip(fn.apply(a).fmap(b -> bs -> (TravB) wrap(cons(b, ((LambdaIterable) bs).unwrap())))), - (AppTrav) pure.apply((TravB) LambdaIterable.empty()), - as); + public , TravB extends Traversable>, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, + Fn1 pure) { + return FoldRight.foldRight( + (a, lglb) -> fn.apply(a) + .lazyZip(lglb., App>>fmap(appTrav -> appTrav + .fmap(travB -> b -> (TravB) wrap(cons(b, ((LambdaIterable) travB).unwrap()))))) + .fmap(appTrav -> (AppTrav) appTrav), + lazy(pure.apply((TravB) empty())), + as + ).value(); } @Override public boolean equals(Object other) { if (other instanceof LambdaIterable) { Iterator xs = as.iterator(); - Iterator ys = ((LambdaIterable) other).as.iterator(); + Iterator ys = ((LambdaIterable) other).as.iterator(); while (xs.hasNext() && ys.hasNext()) if (!Objects.equals(xs.next(), ys.next())) diff --git a/src/main/java/com/jnape/palatable/lambda/traversable/LambdaMap.java b/src/main/java/com/jnape/palatable/lambda/traversable/LambdaMap.java index 20205a419..f8e8c7fd2 100644 --- a/src/main/java/com/jnape/palatable/lambda/traversable/LambdaMap.java +++ b/src/main/java/com/jnape/palatable/lambda/traversable/LambdaMap.java @@ -1,6 +1,6 @@ package com.jnape.palatable.lambda.traversable; -import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Functor; @@ -8,9 +8,9 @@ import java.util.HashMap; import java.util.Map; import java.util.Objects; -import java.util.function.Function; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.Fn2.curried; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; import static com.jnape.palatable.lambda.functions.builtin.fn2.ToMap.toMap; @@ -40,20 +40,21 @@ public Map unwrap() { } @Override - public LambdaMap fmap(Function fn) { + public LambdaMap fmap(Fn1 fn) { return wrap(toMap(HashMap::new, map(entry -> tuple(entry.getKey(), fn.apply(entry.getValue())), map.entrySet()))); } @Override @SuppressWarnings("unchecked") - public >, AppC extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { - return foldLeft(Fn2., AppTrav>fn2(appTrav -> into((k, appV) -> (AppTrav) appTrav.zip(appV.fmap(v -> m -> { + public , TravC extends Traversable>, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, + Fn1 pure) { + return foldLeft(curried(appTrav -> into((k, appV) -> (AppTrav) appTrav.zip(appV.fmap(v -> m -> { ((LambdaMap) m).unwrap().put(k, v); - return (TravC) m; - })))).toBiFunction(), + return m; + })))), pure.apply((TravC) LambdaMap.wrap(new HashMap<>())), - this.fmap(fn).unwrap().entrySet()); + this.fmap(fn).unwrap().entrySet()); } @Override diff --git a/src/main/java/com/jnape/palatable/lambda/traversable/Traversable.java b/src/main/java/com/jnape/palatable/lambda/traversable/Traversable.java index aff6884da..54caa1317 100644 --- a/src/main/java/com/jnape/palatable/lambda/traversable/Traversable.java +++ b/src/main/java/com/jnape/palatable/lambda/traversable/Traversable.java @@ -1,11 +1,10 @@ package com.jnape.palatable.lambda.traversable; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.builtin.Identity; -import java.util.function.Function; - /** * An interface for a class of data structures that can be "traversed from left to right" in a structure-preserving * way, successively applying some applicative computation to each element and collapsing the results into a single @@ -30,27 +29,29 @@ * @param The type of the parameter * @param The unification parameter */ -public interface Traversable extends Functor { +public interface Traversable> extends Functor { /** * Apply fn to each element of this traversable from left to right, and collapse the results into * a single resulting applicative, potentially with the assistance of the applicative's pure function. * - * @param fn the function to apply - * @param pure the applicative pure function * @param the resulting element type * @param the result applicative type * @param this Traversable instance over B - * @param the result applicative instance over B * @param the full inferred resulting type from the traversal + * @param fn the function to apply + * @param pure the applicative pure function * @return the traversed Traversable, wrapped inside an applicative */ - , AppB extends Applicative, + , TravB extends Traversable, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure); + Fn1> fn, Fn1 pure); + /** + * {@inheritDoc} + */ @Override - default Traversable fmap(Function fn) { + default Traversable fmap(Fn1 fn) { return traverse(a -> new Identity(fn.apply(a)), Identity::new).runIdentity(); } } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java b/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java index e43e2438f..37371ead6 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java @@ -1,5 +1,6 @@ package com.jnape.palatable.lambda.adt; +import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.framework.Subjects; import com.jnape.palatable.traitor.runners.Traits; @@ -15,7 +16,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.BiFunction; import static com.jnape.palatable.lambda.adt.Either.fromMaybe; import static com.jnape.palatable.lambda.adt.Either.left; @@ -23,6 +23,8 @@ import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.adt.Unit.UNIT; +import static com.jnape.palatable.lambda.functions.Effect.fromConsumer; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertEquals; @@ -41,7 +43,7 @@ public Subjects> testSubjects() { @Test public void recoverLiftsLeftAndFlattensRight() { - Either left = left("foo"); + Either left = left("foo"); Either right = right(1); assertThat(left.recover(l -> -1), is(-1)); @@ -50,7 +52,7 @@ public void recoverLiftsLeftAndFlattensRight() { @Test public void forfeitLiftsRightAndFlattensLeft() { - Either left = left("foo"); + Either left = left("foo"); Either right = right(1); assertThat(left.forfeit(r -> "bar"), is("foo")); @@ -59,7 +61,7 @@ public void forfeitLiftsRightAndFlattensLeft() { @Test public void orReplacesLeftAndFlattensRight() { - Either left = left("foo"); + Either left = left("foo"); Either right = right(1); assertThat(left.or(-1), is(-1)); @@ -68,7 +70,7 @@ public void orReplacesLeftAndFlattensRight() { @Test public void orThrowFlattensRightOrThrowsException() { - Either left = left("foo"); + Either left = left("foo"); Either right = right(1); assertThat(right.orThrow(IllegalStateException::new), is(1)); @@ -81,7 +83,7 @@ public void orThrowFlattensRightOrThrowsException() { @Test public void filterLiftsRight() { - Either left = left("foo"); + Either left = left("foo"); Either right = right(1); assertThat(left.filter(x -> true, () -> "bar"), is(left)); @@ -92,7 +94,7 @@ public void filterLiftsRight() { @Test public void filterSupportsFunctionFromRToL() { - Either left = left("foo"); + Either left = left("foo"); Either right = right(1); assertThat(left.filter(x -> true, Object::toString), is(left)); @@ -103,7 +105,7 @@ public void filterSupportsFunctionFromRToL() { @Test public void monadicFlatMapLiftsRightAndFlattensBackToEither() { - Either left = left("foo"); + Either left = left("foo"); Either right = right(1); assertThat(left.flatMap(r -> right(r + 1)), is(left("foo"))); @@ -112,14 +114,14 @@ public void monadicFlatMapLiftsRightAndFlattensBackToEither() { @Test public void mergeDuallyLiftsAndCombinesBiasingLeft() { - Either left1 = left("foo"); + Either left1 = left("foo"); Either right1 = right(1); - Either left2 = left("bar"); + Either left2 = left("bar"); Either right2 = right(2); - BiFunction concat = String::concat; - BiFunction add = (r1, r2) -> r1 + r2; + Fn2 concat = String::concat; + Fn2 add = Integer::sum; assertThat(left1.merge(concat, add, left2), is(left("foobar"))); assertThat(left1.merge(concat, add, right2), is(left1)); @@ -129,7 +131,7 @@ public void mergeDuallyLiftsAndCombinesBiasingLeft() { @Test public void matchDuallyLiftsAndFlattens() { - Either left = left("foo"); + Either left = left("foo"); Either right = right(1); assertThat(left.match(l -> l + "bar", r -> r + 1), is("foobar")); @@ -144,7 +146,7 @@ public void toMaybeMapsEitherToOptional() { @Test public void fromMaybeMapsMaybeToEither() { - Maybe just = just(1); + Maybe just = just(1); Maybe nothing = nothing(); assertThat(fromMaybe(just, () -> "fail"), is(right(1))); @@ -153,8 +155,8 @@ public void fromMaybeMapsMaybeToEither() { @Test public void fromMaybeDoesNotEvaluateLeftFnForRight() { - Maybe just = just(1); - AtomicInteger atomicInteger = new AtomicInteger(0); + Maybe just = just(1); + AtomicInteger atomicInteger = new AtomicInteger(0); fromMaybe(just, atomicInteger::incrementAndGet); assertThat(atomicInteger.get(), is(0)); @@ -195,32 +197,40 @@ public void monadTryingWithRunnable() { @Test public void monadicPeekLiftsIOToTheRight() { - Either left = left("foo"); + Either left = left("foo"); Either right = right(1); AtomicInteger intRef = new AtomicInteger(); - left.peek(intRef::set); + left.peek(fromConsumer(intRef::set)); assertEquals(0, intRef.get()); - right.peek(intRef::set); + right.peek(fromConsumer(intRef::set)); assertEquals(1, intRef.get()); } @Test public void dyadicPeekDuallyLiftsIO() { - Either left = left("foo"); + Either left = left("foo"); Either right = right(1); AtomicReference stringRef = new AtomicReference<>(); - AtomicInteger intRef = new AtomicInteger(); + AtomicInteger intRef = new AtomicInteger(); - left.peek(stringRef::set, intRef::set); + left.peek(fromConsumer(stringRef::set), fromConsumer(intRef::set)); assertEquals("foo", stringRef.get()); assertEquals(0, intRef.get()); - right.peek(stringRef::set, intRef::set); + right.peek(fromConsumer(stringRef::set), fromConsumer(intRef::set)); assertEquals("foo", stringRef.get()); assertEquals(1, intRef.get()); } + + @Test + public void lazyZip() { + assertEquals(right(2), right(1).lazyZip(lazy(right(x -> x + 1))).value()); + assertEquals(left("foo"), left("foo").lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java b/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java index 1e747dc34..0548e74f4 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java @@ -21,7 +21,10 @@ import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn2.Eq.eq; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; +import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; @@ -96,10 +99,10 @@ public void fromEither() { @Test public void peek() { AtomicInteger ref = new AtomicInteger(0); - assertEquals(just(1), just(1).peek(__ -> ref.incrementAndGet())); + assertEquals(just(1), just(1).peek(constantly(io(ref::incrementAndGet)))); assertEquals(1, ref.get()); - assertEquals(nothing(), nothing().peek(__ -> ref.incrementAndGet())); + assertEquals(nothing(), nothing().peek(constantly(io(ref::incrementAndGet)))); assertEquals(1, ref.get()); } @@ -130,4 +133,12 @@ public void invertsIntoChoice2() { assertEquals(Choice2.b(UNIT), nothing().invert()); assertEquals(Choice2.a(1), just(1).invert()); } + + @Test + public void lazyZip() { + assertEquals(just(2), just(1).lazyZip(lazy(() -> just(x -> x + 1))).value()); + assertEquals(nothing(), nothing().lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/TheseTest.java b/src/test/java/com/jnape/palatable/lambda/adt/TheseTest.java index ba44c9caf..c4484c1a3 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/TheseTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/TheseTest.java @@ -3,6 +3,7 @@ import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.framework.Subjects; import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; import org.junit.runner.RunWith; import testsupport.traits.ApplicativeLaws; import testsupport.traits.BifunctorLaws; @@ -13,7 +14,9 @@ import static com.jnape.palatable.lambda.adt.These.a; import static com.jnape.palatable.lambda.adt.These.b; import static com.jnape.palatable.lambda.adt.These.both; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.traitor.framework.Subjects.subjects; +import static org.junit.Assert.assertEquals; @RunWith(Traits.class) public class TheseTest { @@ -22,4 +25,15 @@ public class TheseTest { public Subjects> testSubject() { return subjects(a("foo"), b(1), both("foo", 1)); } + + @Test + public void lazyZip() { + assertEquals(b(2), b(1).lazyZip(lazy(b(x -> x + 1))).value()); + assertEquals(b(2), b(1).lazyZip(lazy(both("foo", x -> x + 1))).value()); + assertEquals(both("bar", 2), both("foo", 1).lazyZip(lazy(both("bar", x -> x + 1))).value()); + assertEquals(both("foo", 2), both("foo", 1).lazyZip(lazy(b(x -> x + 1))).value()); + assertEquals(a(1), a(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java b/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java index f0c7cb043..ee6ad0dd7 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java @@ -27,6 +27,7 @@ import static com.jnape.palatable.lambda.adt.Try.trying; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static java.util.Arrays.asList; import static org.hamcrest.CoreMatchers.equalTo; @@ -35,6 +36,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static testsupport.matchers.LeftMatcher.isLeftThat; @RunWith(Traits.class) @@ -43,13 +45,13 @@ public class TryTest { @Rule public ExpectedException thrown = ExpectedException.none(); @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, TraversableLaws.class}) - public Subjects> testSubject() { + public Subjects> testSubject() { return subjects(failure(new IllegalStateException()), success(1)); } @Test public void catchingWithGenericPredicate() { - Try caught = Try.failure(new RuntimeException()) + Try caught = Try.failure(new RuntimeException()) .catching(__ -> false, r -> "caught first") .catching(__ -> true, r -> "caught second"); @@ -58,7 +60,7 @@ public void catchingWithGenericPredicate() { @Test public void catchingIsANoOpForSuccess() { - Try caught = Try.success("success") + Try caught = success("success") .catching(__ -> true, __ -> "caught"); assertEquals(success("success"), caught); @@ -66,7 +68,7 @@ public void catchingIsANoOpForSuccess() { @Test public void firstMatchingCatchBlockWins() { - Try caught = Try.failure(new IllegalStateException()) + Try caught = Try.failure(new IllegalStateException()) .catching(__ -> true, __ -> "first") .catching(__ -> true, __ -> "second"); @@ -75,7 +77,7 @@ public void firstMatchingCatchBlockWins() { @Test public void catchBasedOnExceptionType() { - Try caught = Try.failure(new IllegalStateException()) + Try caught = Try.failure(new IllegalStateException()) .catching(IllegalArgumentException.class, __ -> "illegal argument exception") .catching(IllegalStateException.class, __ -> "illegal state exception") .catching(RuntimeException.class, __ -> "runtime exception"); @@ -86,7 +88,7 @@ public void catchBasedOnExceptionType() { @Test public void ensureIfSuccess() { AtomicInteger invocations = new AtomicInteger(0); - Try.success(1).ensuring((invocations::incrementAndGet)); + success(1).ensuring((invocations::incrementAndGet)); assertEquals(1, invocations.get()); } @@ -100,9 +102,9 @@ public void ensureIfFailure() { @Test public void exceptionThrownInEnsuringBlockIsCaught() { IllegalStateException expected = new IllegalStateException(); - assertEquals(Try.failure(expected), Try.success(1).ensuring(() -> {throw expected;})); + assertEquals(Try.failure(expected), success(1).ensuring(() -> {throw expected;})); - Either actual = Try.failure(new IllegalArgumentException()) + Either actual = Try.failure(new IllegalArgumentException()) .ensuring(() -> { throw expected;}) .toEither(); assertThat(actual, isLeftThat(instanceOf(IllegalArgumentException.class))); @@ -112,14 +114,14 @@ public void exceptionThrownInEnsuringBlockIsCaught() { @Test public void forfeitEnsuresFailure() { IllegalStateException expected = new IllegalStateException(); - assertEquals(expected, Try.failure(expected).forfeit(__ -> new IllegalArgumentException())); - assertEquals(expected, Try.success(1).forfeit(__ -> expected)); + assertEquals(expected, Try.failure(expected).forfeit(__ -> new IllegalArgumentException())); + assertEquals(expected, Try.success(1).forfeit(__ -> expected)); } @Test public void recoverEnsuresSuccess() { - assertEquals((Integer) 1, Try.success(1).recover(constantly(1))); - assertEquals((Integer) 1, Try.failure(new IllegalArgumentException()).recover(constantly(1))); + assertEquals((Integer) 1, Try.success(1).recover(constantly(1))); + assertEquals((Integer) 1, Try.failure(new IllegalArgumentException()).recover(constantly(1))); } @Test @@ -133,13 +135,13 @@ public void orThrow() throws Throwable { @Test public void toMaybe() { - assertEquals(just("foo"), Try.success("foo").toMaybe()); + assertEquals(just("foo"), success("foo").toMaybe()); assertEquals(nothing(), Try.failure(new IllegalStateException()).toMaybe()); } @Test public void toEither() { - assertEquals(right("foo"), Try.success("foo").toEither()); + assertEquals(right("foo"), success("foo").toEither()); IllegalStateException exception = new IllegalStateException(); assertEquals(left(exception), Try.failure(exception).toEither()); @@ -147,7 +149,7 @@ public void toEither() { @Test public void toEitherWithLeftMappingFunction() { - assertEquals(right(1), Try.success(1).toEither(__ -> "fail")); + assertEquals(right(1), success(1).toEither(__ -> "fail")); assertEquals(left("fail"), Try.failure(new IllegalStateException("fail")).toEither(Throwable::getMessage)); } @@ -162,13 +164,13 @@ public void tryingCatchesAnyThrowableThrownDuringEvaluation() { @Test public void withResourcesCleansUpAutoCloseableInSuccessCase() { AtomicBoolean closed = new AtomicBoolean(false); - assertEquals(Try.success(1), Try.withResources(() -> () -> closed.set(true), resource -> success(1))); + assertEquals(success(1), Try.withResources(() -> () -> closed.set(true), resource -> success(1))); assertTrue(closed.get()); } @Test public void withResourcesCleansUpAutoCloseableInFailureCase() { - AtomicBoolean closed = new AtomicBoolean(false); + AtomicBoolean closed = new AtomicBoolean(false); RuntimeException exception = new RuntimeException(); assertEquals(Try.failure(exception), Try.withResources(() -> () -> closed.set(true), resource -> { throw exception; })); @@ -190,11 +192,11 @@ public void withResourcesExposesResourceCloseFailure() { @Test public void withResourcesPreservesSuppressedExceptionThrownDuringClose() { - RuntimeException rootException = new RuntimeException(); - IOException nestedIOException = new IOException(); - Try failure = Try.withResources(() -> () -> { throw nestedIOException; }, - resource -> { throw rootException; }); - Exception thrown = failure.recover(id()); + RuntimeException rootException = new RuntimeException(); + IOException nestedIOException = new IOException(); + Try failure = Try.withResources(() -> () -> { throw nestedIOException; }, + resource -> { throw rootException; }); + Throwable thrown = failure.recover(id()); assertEquals(thrown, rootException); assertArrayEquals(new Throwable[]{nestedIOException}, thrown.getSuppressed()); @@ -209,4 +211,41 @@ public void cascadingWithResourcesClosesInInverseOrder() { c -> success(1))); assertEquals(asList("close c", "close b", "close a"), closeMessages); } + + @Test + public void lazyZip() { + assertEquals(success(2), success(1).lazyZip(lazy(success(x -> x + 1))).value()); + IllegalStateException e = new IllegalStateException(); + assertEquals(failure(e), failure(e).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } + + @Test + public void orThrowCanStillThrowCheckedExceptions() { + try { + Try.trying(() -> { + throw new RuntimeException(); + }).orThrow(); + fail("Expected RuntimeException to be thrown, but nothing was"); + } catch (IOException ioException) { + fail("Expected thrown exception to not be IOException, but merely proving it can still be caught"); + } catch (Exception expected) { + } + } + + @Test + public void orThrowCanTransformFirst() { + try { + Try.trying(() -> { + throw new IllegalStateException(); + }).orThrow(IllegalArgumentException::new); + fail("Expected RuntimeException to be thrown, but nothing was"); + } catch (IllegalStateException ioException) { + fail("Expected thrown exception to not be IllegalStateException, but it was"); + } catch (IllegalArgumentException expected) { + } catch (Exception e) { + fail("A different exception altogether was thrown."); + } + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice2Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice2Test.java index 49b489192..ea4c27160 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice2Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice2Test.java @@ -14,6 +14,7 @@ import static com.jnape.palatable.lambda.adt.choice.Choice2.a; import static com.jnape.palatable.lambda.adt.choice.Choice2.b; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; @@ -39,4 +40,12 @@ public void divergeStaysInChoice() { assertEquals(Choice3.a(1), a.diverge()); assertEquals(Choice3.b(true), b.diverge()); } + + @Test + public void lazyZip() { + assertEquals(b(2), b(1).lazyZip(lazy(b(x -> x + 1))).value()); + assertEquals(a("foo"), a("foo").lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice3Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice3Test.java index 1d04ec9a5..2deefbb91 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice3Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice3Test.java @@ -15,6 +15,7 @@ import static com.jnape.palatable.lambda.adt.choice.Choice3.a; import static com.jnape.palatable.lambda.adt.choice.Choice3.b; import static com.jnape.palatable.lambda.adt.choice.Choice3.c; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; @@ -50,4 +51,15 @@ public void divergeStaysInChoice() { assertEquals(Choice4.b("two"), b.diverge()); assertEquals(Choice4.c(true), c.diverge()); } + + @Test + public void lazyZip() { + assertEquals(Choice3.c(2), c(1).lazyZip(lazy(c(x -> x + 1))).value()); + assertEquals(Choice3.b(1), b(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(Choice3.a(1), a(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice4Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice4Test.java index 0b70141e7..1e20850d6 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice4Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice4Test.java @@ -16,6 +16,7 @@ import static com.jnape.palatable.lambda.adt.choice.Choice4.b; import static com.jnape.palatable.lambda.adt.choice.Choice4.c; import static com.jnape.palatable.lambda.adt.choice.Choice4.d; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; @@ -55,4 +56,18 @@ public void divergeStaysInChoice() { assertEquals(Choice5.c(true), c.diverge()); assertEquals(Choice5.d(4D), d.diverge()); } + + @Test + public void lazyZip() { + assertEquals(d(2), d(1).lazyZip(lazy(d(x -> x + 1))).value()); + assertEquals(a(1), a(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(b(1), b(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(c(1), c(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice5Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice5Test.java index d0ea885e5..bfccafcb9 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice5Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice5Test.java @@ -17,6 +17,7 @@ import static com.jnape.palatable.lambda.adt.choice.Choice5.c; import static com.jnape.palatable.lambda.adt.choice.Choice5.d; import static com.jnape.palatable.lambda.adt.choice.Choice5.e; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; @@ -60,4 +61,21 @@ public void divergeStaysInChoice() { assertEquals(Choice6.d(4D), d.diverge()); assertEquals(Choice6.e('z'), e.diverge()); } + + @Test + public void lazyZip() { + assertEquals(e(2), e(1).lazyZip(lazy(e(x -> x + 1))).value()); + assertEquals(a(1), a(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(b(1), b(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(c(1), c(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(d(1), d(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice6Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice6Test.java index 2262884b5..f818d4fd7 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice6Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice6Test.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.adt.choice; import com.jnape.palatable.lambda.adt.coproduct.CoProduct5; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.framework.Subjects; import com.jnape.palatable.traitor.runners.Traits; @@ -13,14 +14,13 @@ import testsupport.traits.MonadLaws; import testsupport.traits.TraversableLaws; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.choice.Choice6.a; import static com.jnape.palatable.lambda.adt.choice.Choice6.b; import static com.jnape.palatable.lambda.adt.choice.Choice6.c; import static com.jnape.palatable.lambda.adt.choice.Choice6.d; import static com.jnape.palatable.lambda.adt.choice.Choice6.e; import static com.jnape.palatable.lambda.adt.choice.Choice6.f; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; @@ -51,7 +51,7 @@ public Subjects> test @Test public void convergeStaysInChoice() { - Function> convergenceFn = f -> Choice5.b(f.toString()); + Fn1> convergenceFn = f -> Choice5.b(f.toString()); assertEquals(Choice5.a(1), a.converge(convergenceFn)); assertEquals(Choice5.b("two"), b.converge(convergenceFn)); @@ -70,4 +70,24 @@ public void divergeStaysInChoice() { assertEquals(Choice7.e('z'), e.diverge()); assertEquals(Choice7.f(5L), f.diverge()); } + + @Test + public void lazyZip() { + assertEquals(f(2), f(1).lazyZip(lazy(f(x -> x + 1))).value()); + assertEquals(a(1), a(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(b(1), b(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(c(1), c(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(d(1), d(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(e(1), e(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice7Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice7Test.java index 27bf111d0..62f2e52d0 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice7Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice7Test.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.adt.choice; import com.jnape.palatable.lambda.adt.coproduct.CoProduct6; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.framework.Subjects; import com.jnape.palatable.traitor.runners.Traits; @@ -13,8 +14,6 @@ import testsupport.traits.MonadLaws; import testsupport.traits.TraversableLaws; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.choice.Choice7.a; import static com.jnape.palatable.lambda.adt.choice.Choice7.b; import static com.jnape.palatable.lambda.adt.choice.Choice7.c; @@ -22,6 +21,7 @@ import static com.jnape.palatable.lambda.adt.choice.Choice7.e; import static com.jnape.palatable.lambda.adt.choice.Choice7.f; import static com.jnape.palatable.lambda.adt.choice.Choice7.g; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; @@ -54,7 +54,7 @@ public Subjects> convergenceFn = g -> Choice6.b(g.toString()); + Fn1> convergenceFn = g -> Choice6.b(g.toString()); assertEquals(Choice6.a(1), a.converge(convergenceFn)); assertEquals(Choice6.b("two"), b.converge(convergenceFn)); @@ -75,4 +75,27 @@ public void divergeStaysInChoice() { assertEquals(Choice8.f(5L), f.diverge()); assertEquals(Choice8.g(6F), g.diverge()); } + + @Test + public void lazyZip() { + assertEquals(g(2), g(1).lazyZip(lazy(g(x -> x + 1))).value()); + assertEquals(a(1), a(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(b(1), b(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(c(1), c(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(d(1), d(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(e(1), e(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(f(1), f(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice8Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice8Test.java index 24fede69b..2b3d4dbe7 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice8Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice8Test.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.adt.choice; import com.jnape.palatable.lambda.adt.coproduct.CoProduct7; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.framework.Subjects; import com.jnape.palatable.traitor.runners.Traits; @@ -13,8 +14,6 @@ import testsupport.traits.MonadLaws; import testsupport.traits.TraversableLaws; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.choice.Choice8.a; import static com.jnape.palatable.lambda.adt.choice.Choice8.b; import static com.jnape.palatable.lambda.adt.choice.Choice8.c; @@ -23,6 +22,7 @@ import static com.jnape.palatable.lambda.adt.choice.Choice8.f; import static com.jnape.palatable.lambda.adt.choice.Choice8.g; import static com.jnape.palatable.lambda.adt.choice.Choice8.h; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; @@ -57,7 +57,8 @@ public Subjects> convergenceFn = h -> Choice7.b(h.toString()); + Fn1> convergenceFn = + h -> Choice7.b(h.toString()); assertEquals(Choice7.a(1), a.converge(convergenceFn)); assertEquals(Choice7.b("two"), b.converge(convergenceFn)); @@ -68,4 +69,30 @@ public void convergeStaysInChoice() { assertEquals(Choice7.g(6F), g.converge(convergenceFn)); assertEquals(Choice7.b("7"), h.converge(convergenceFn)); } + + @Test + public void lazyZip() { + assertEquals(h(2), h(1).lazyZip(lazy(h(x -> x + 1))).value()); + assertEquals(a(1), a(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(b(1), b(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(c(1), c(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(d(1), d(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(e(1), e(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(f(1), f(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(g(1), g(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct2Test.java b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct2Test.java index 8b3d8f978..d5a07cca6 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct2Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct2Test.java @@ -1,11 +1,10 @@ package com.jnape.palatable.lambda.adt.coproduct; import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.functions.Fn1; import org.junit.Before; import org.junit.Test; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; @@ -21,13 +20,13 @@ public class CoProduct2Test { public void setUp() { a = new CoProduct2>() { @Override - public R match(Function aFn, Function bFn) { + public R match(Fn1 aFn, Fn1 bFn) { return aFn.apply(1); } }; b = new CoProduct2>() { @Override - public R match(Function aFn, Function bFn) { + public R match(Fn1 aFn, Fn1 bFn) { return bFn.apply(true); } }; diff --git a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct3Test.java b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct3Test.java index 49af8665c..c80a50be2 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct3Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct3Test.java @@ -3,11 +3,10 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.choice.Choice2; import com.jnape.palatable.lambda.adt.choice.Choice3; +import com.jnape.palatable.lambda.functions.Fn1; import org.junit.Before; import org.junit.Test; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; @@ -24,22 +23,22 @@ public class CoProduct3Test { public void setUp() { a = new CoProduct3>() { @Override - public R match(Function aFn, Function bFn, - Function cFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn) { return aFn.apply(1); } }; b = new CoProduct3>() { @Override - public R match(Function aFn, Function bFn, - Function cFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn) { return bFn.apply("two"); } }; c = new CoProduct3>() { @Override - public R match(Function aFn, Function bFn, - Function cFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn) { return cFn.apply(true); } }; @@ -61,7 +60,7 @@ public void diverge() { @Test public void converge() { - Function> convergenceFn = x -> x ? Choice2.a(-1) : Choice2.b("false"); + Fn1> convergenceFn = x -> x ? Choice2.a(-1) : Choice2.b("false"); assertEquals(1, a.converge(convergenceFn).match(id(), id())); assertEquals("two", b.converge(convergenceFn).match(id(), id())); assertEquals(-1, c.converge(convergenceFn).match(id(), id())); diff --git a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4Test.java b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4Test.java index 840416088..810a1781c 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4Test.java @@ -3,11 +3,10 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.choice.Choice3; import com.jnape.palatable.lambda.adt.choice.Choice4; +import com.jnape.palatable.lambda.functions.Fn1; import org.junit.Before; import org.junit.Test; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; @@ -25,29 +24,29 @@ public class CoProduct4Test { public void setUp() { a = new CoProduct4>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn) { return aFn.apply(1); } }; b = new CoProduct4>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn) { return bFn.apply("two"); } }; c = new CoProduct4>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn) { return cFn.apply(true); } }; d = new CoProduct4>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn) { return dFn.apply(4D); } }; @@ -71,11 +70,12 @@ public void diverge() { @Test public void converge() { - Function> convergenceFn = x -> x.equals(1d) - ? Choice3.a(1) - : x.equals(2d) - ? Choice3.b("b") - : Choice3.c(false); + Fn1> convergenceFn = x -> + x.equals(1d) + ? Choice3.a(1) + : x.equals(2d) + ? Choice3.b("b") + : Choice3.c(false); assertEquals(1, a.converge(convergenceFn).match(id(), id(), id())); assertEquals("two", b.converge(convergenceFn).match(id(), id(), id())); assertEquals(true, c.converge(convergenceFn).match(id(), id(), id())); diff --git a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct5Test.java b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct5Test.java index 14cccc369..bd986dea1 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct5Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct5Test.java @@ -3,11 +3,10 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.choice.Choice4; import com.jnape.palatable.lambda.adt.choice.Choice5; +import com.jnape.palatable.lambda.functions.Fn1; import org.junit.Before; import org.junit.Test; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; @@ -26,41 +25,41 @@ public class CoProduct5Test { public void setUp() { a = new CoProduct5>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn) { return aFn.apply(1); } }; b = new CoProduct5>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn) { return bFn.apply("two"); } }; c = new CoProduct5>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn) { return cFn.apply(true); } }; d = new CoProduct5>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn) { return dFn.apply(4d); } }; e = new CoProduct5>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn) { return eFn.apply('z'); } }; @@ -86,13 +85,13 @@ public void diverge() { @Test public void converge() { - Function> convergenceFn = x -> x.equals('a') - ? Choice4.a(1) - : x.equals('b') - ? Choice4.b("b") - : x.equals('c') - ? Choice4.c(false) - : Choice4.d(1D); + Fn1> convergenceFn = x -> x.equals('a') + ? Choice4.a(1) + : x.equals('b') + ? Choice4.b("b") + : x.equals('c') + ? Choice4.c(false) + : Choice4.d(1D); assertEquals(1, a.converge(convergenceFn).match(id(), id(), id(), id())); assertEquals("two", b.converge(convergenceFn).match(id(), id(), id(), id())); assertEquals(true, c.converge(convergenceFn).match(id(), id(), id(), id())); diff --git a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct6Test.java b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct6Test.java index 8c38290e7..924e0507f 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct6Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct6Test.java @@ -3,11 +3,10 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.choice.Choice5; import com.jnape.palatable.lambda.adt.choice.Choice6; +import com.jnape.palatable.lambda.functions.Fn1; import org.junit.Before; import org.junit.Test; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; @@ -27,49 +26,49 @@ public class CoProduct6Test { public void setUp() { a = new CoProduct6>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn) { return aFn.apply(1); } }; b = new CoProduct6>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn) { return bFn.apply("two"); } }; c = new CoProduct6>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn) { return cFn.apply(true); } }; d = new CoProduct6>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn) { return dFn.apply(4D); } }; e = new CoProduct6>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn) { return eFn.apply('z'); } }; f = new CoProduct6>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn) { return fFn.apply(5L); } }; @@ -97,7 +96,7 @@ public void diverge() { @Test public void converge() { - Function> convergenceFn = x -> + Fn1> convergenceFn = x -> x.equals(1L) ? Choice5.a(1) : x.equals(2L) diff --git a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct7Test.java b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct7Test.java index 1ae73c596..84999f677 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct7Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct7Test.java @@ -3,11 +3,10 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.choice.Choice6; import com.jnape.palatable.lambda.adt.choice.Choice7; +import com.jnape.palatable.lambda.functions.Fn1; import org.junit.Before; import org.junit.Test; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; @@ -28,64 +27,64 @@ public class CoProduct7Test { public void setUp() { a = new CoProduct7>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn) { return aFn.apply(1); } }; b = new CoProduct7>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn) { return bFn.apply("two"); } }; c = new CoProduct7>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn) { return cFn.apply(true); } }; d = new CoProduct7>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn) { return dFn.apply(4D); } }; e = new CoProduct7>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn) { return eFn.apply('z'); } }; f = new CoProduct7>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn) { return fFn.apply(5L); } }; g = new CoProduct7>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn) { return gFn.apply(6f); } }; @@ -115,7 +114,7 @@ public void diverge() { @Test public void converge() { - Function> convergenceFn = x -> + Fn1> convergenceFn = x -> x.equals(1f) ? Choice6.a(1) : x.equals(2f) diff --git a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct8Test.java b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct8Test.java index e85f3152a..e5620b3c0 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct8Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct8Test.java @@ -3,11 +3,10 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.choice.Choice7; import com.jnape.palatable.lambda.adt.choice.Choice8; +import com.jnape.palatable.lambda.functions.Fn1; import org.junit.Before; import org.junit.Test; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; @@ -29,73 +28,73 @@ public class CoProduct8Test { public void setUp() { a = new CoProduct8>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn, Function hFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn, Fn1 hFn) { return aFn.apply(1); } }; b = new CoProduct8>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn, Function hFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn, Fn1 hFn) { return bFn.apply("two"); } }; c = new CoProduct8>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn, Function hFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn, Fn1 hFn) { return cFn.apply(true); } }; d = new CoProduct8>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn, Function hFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn, Fn1 hFn) { return dFn.apply(4D); } }; e = new CoProduct8>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn, Function hFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn, Fn1 hFn) { return eFn.apply('z'); } }; f = new CoProduct8>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn, Function hFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn, Fn1 hFn) { return fFn.apply(5L); } }; g = new CoProduct8>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn, Function hFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn, Fn1 hFn) { return gFn.apply(6f); } }; h = new CoProduct8>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn, Function hFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn, Fn1 hFn) { return hFn.apply((short) 7); } }; @@ -115,7 +114,7 @@ public void match() { @Test public void converge() { - Function> convergenceFn = x -> + Fn1> convergenceFn = x -> x.equals((short) 1) ? Choice7.a(1) : x.equals((short) 2) diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/SingletonHListTest.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/SingletonHListTest.java index 56d3c19d5..aae10e80e 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/SingletonHListTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/SingletonHListTest.java @@ -25,7 +25,7 @@ public void setUp() { } @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, TraversableLaws.class}) - public SingletonHList testSubject() { + public SingletonHList testSubject() { return singletonHList("one"); } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java index a5e86f825..75d4bcbe2 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java @@ -1,5 +1,6 @@ package com.jnape.palatable.lambda.adt.hlist; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Before; @@ -13,7 +14,6 @@ import java.util.HashMap; import java.util.Map; -import java.util.function.Function; import static com.jnape.palatable.lambda.adt.hlist.HList.singletonHList; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; @@ -34,7 +34,7 @@ public void setUp() { } @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) - public Tuple2 testSubject() { + public Tuple2 testSubject() { return tuple("one", 2); } @@ -62,7 +62,7 @@ public void accessors() { @Test public void randomAccess() { SingletonHList spiedTail = spy(singletonHList("second")); - Tuple2 tuple2 = new Tuple2<>("first", spiedTail); + Tuple2 tuple2 = new Tuple2<>("first", spiedTail); verify(spiedTail, only()).head(); tuple2._1(); @@ -93,6 +93,7 @@ public void setValueIsNotSupported() { } @Test + @SuppressWarnings("serial") public void staticFactoryMethodFromMapEntry() { Map.Entry stringIntEntry = new HashMap() {{ put("string", 1); @@ -103,15 +104,15 @@ public void staticFactoryMethodFromMapEntry() { @Test public void zipPrecedence() { - Tuple2 a = tuple("foo", 1); - Tuple2> b = tuple("bar", x -> x + 1); + Tuple2 a = tuple("foo", 1); + Tuple2> b = tuple("bar", x -> x + 1); assertEquals(tuple("bar", 2), a.zip(b)); } @Test public void flatMapPrecedence() { - Tuple2 a = tuple("foo", 1); - Function> b = x -> tuple("bar", x + 1); + Tuple2 a = tuple("foo", 1); + Fn1> b = x -> tuple("bar", x + 1); assertEquals(tuple("foo", 2), a.flatMap(b)); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java index 0730a97a9..d52b407bb 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java @@ -1,5 +1,6 @@ package com.jnape.palatable.lambda.adt.hlist; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Before; @@ -11,8 +12,6 @@ import testsupport.traits.MonadLaws; import testsupport.traits.TraversableLaws; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.spy; @@ -31,7 +30,7 @@ public void setUp() { } @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) - public Tuple3 testSubject() { + public Tuple3 testSubject() { return tuple("one", 2, 3d); } @@ -83,15 +82,15 @@ public void fill() { @Test public void zipPrecedence() { - Tuple3 a = tuple("foo", 1, 2); - Tuple3> b = tuple("bar", 2, x -> x + 1); + Tuple3 a = tuple("foo", 1, 2); + Tuple3> b = tuple("bar", 2, x -> x + 1); assertEquals(tuple("foo", 1, 3), a.zip(b)); } @Test public void flatMapPrecedence() { - Tuple3 a = tuple("foo", 1, 2); - Function> b = x -> tuple("bar", 2, x + 1); + Tuple3 a = tuple("foo", 1, 2); + Fn1> b = x -> tuple("bar", 2, x + 1); assertEquals(tuple("foo", 1, 3), a.flatMap(b)); } } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java index 44a6ba8dc..4e0fa9659 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java @@ -1,5 +1,6 @@ package com.jnape.palatable.lambda.adt.hlist; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Before; @@ -11,8 +12,6 @@ import testsupport.traits.MonadLaws; import testsupport.traits.TraversableLaws; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.spy; @@ -31,7 +30,7 @@ public void setUp() { } @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) - public Tuple4 testSubject() { + public Tuple4 testSubject() { return tuple("one", 2, 3d, 4f); } @@ -60,8 +59,8 @@ public void accessors() { @Test public void randomAccess() { - Tuple3 spiedTail = spy(tuple("second", "third", "fourth")); - Tuple4 tuple4 = new Tuple4<>("first", spiedTail); + Tuple3 spiedTail = spy(tuple("second", "third", "fourth")); + Tuple4 tuple4 = new Tuple4<>("first", spiedTail); verify(spiedTail, times(1))._1(); verify(spiedTail, times(1))._2(); @@ -86,15 +85,15 @@ public void fill() { @Test public void zipPrecedence() { - Tuple4 a = tuple("foo", 1, 2, 3); - Tuple4> b = tuple("foo", 1, 2, x -> x + 1); + Tuple4 a = tuple("foo", 1, 2, 3); + Tuple4> b = tuple("foo", 1, 2, x -> x + 1); assertEquals(tuple("foo", 1, 2, 4), a.zip(b)); } @Test public void flatMapPrecedence() { - Tuple4 a = tuple("foo", 1, 2, 3); - Function> b = x -> tuple("bar", 2, 3, x + 1); + Tuple4 a = tuple("foo", 1, 2, 3); + Fn1> b = x -> tuple("bar", 2, 3, x + 1); assertEquals(tuple("foo", 1, 2, 4), a.flatMap(b)); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java index 248dd03e1..45e4edc67 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.adt.hlist; import com.jnape.palatable.lambda.adt.hlist.HList.HCons; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Before; @@ -12,8 +13,6 @@ import testsupport.traits.MonadLaws; import testsupport.traits.TraversableLaws; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.spy; @@ -32,7 +31,7 @@ public void setUp() { } @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) - public Tuple5 testSubject() { + public Tuple5 testSubject() { return tuple("one", 2, 3d, 4f, '5'); } @@ -62,8 +61,8 @@ public void accessors() { @Test public void randomAccess() { - Tuple4 spiedTail = spy(tuple("second", "third", "fourth", "fifth")); - Tuple5 tuple5 = new Tuple5<>("first", spiedTail); + Tuple4 spiedTail = spy(tuple("second", "third", "fourth", "fifth")); + Tuple5 tuple5 = new Tuple5<>("first", spiedTail); verify(spiedTail, times(1))._1(); verify(spiedTail, times(1))._2(); @@ -90,15 +89,17 @@ public void fill() { @Test public void zipPrecedence() { - Tuple5 a = tuple("foo", 1, 2, 3, 4); - Tuple5> b = tuple("bar", 2, 3, 4, x -> x + 1); + Tuple5 a = + tuple("foo", 1, 2, 3, 4); + Tuple5> b = + tuple("bar", 2, 3, 4, x -> x + 1); assertEquals(tuple("bar", 2, 3, 4, 5), a.zip(b)); } @Test public void flatMapPrecedence() { - Tuple5 a = tuple("foo", 1, 2, 3, 4); - Function> b = x -> tuple("bar", 2, 3, 4, x + 1); + Tuple5 a = tuple("foo", 1, 2, 3, 4); + Fn1> b = x -> tuple("bar", 2, 3, 4, x + 1); assertEquals(tuple("foo", 1, 2, 3, 5), a.flatMap(b)); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java index bd31aca1a..1fb7ab578 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.adt.hlist; import com.jnape.palatable.lambda.adt.hlist.HList.HCons; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Before; @@ -12,8 +13,6 @@ import testsupport.traits.MonadLaws; import testsupport.traits.TraversableLaws; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.spy; @@ -32,7 +31,7 @@ public void setUp() { } @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) - public Tuple6 testSubject() { + public Tuple6 testSubject() { return tuple("one", 2, 3d, 4f, '5', (byte) 6); } @@ -64,8 +63,8 @@ public void accessors() { @Test public void randomAccess() { - Tuple5 spiedTail = spy(tuple("second", "third", "fourth", "fifth", "sixth")); - Tuple6 tuple6 = new Tuple6<>("first", spiedTail); + Tuple5 spiedTail = spy(tuple("second", "third", "fourth", "fifth", "sixth")); + Tuple6 tuple6 = new Tuple6<>("first", spiedTail); verify(spiedTail, times(1))._1(); verify(spiedTail, times(1))._2(); @@ -94,15 +93,17 @@ public void fill() { @Test public void zipPrecedence() { - Tuple6 a = tuple("foo", 1, 2, 3, 4, 5); - Tuple6> b = tuple("bar", 2, 3, 4, 5, x -> x + 1); + Tuple6 a = + tuple("foo", 1, 2, 3, 4, 5); + Tuple6> b = + tuple("bar", 2, 3, 4, 5, x -> x + 1); assertEquals(tuple("bar", 2, 3, 4, 5, 6), a.zip(b)); } @Test public void flatMapPrecedence() { - Tuple6 a = tuple("foo", 1, 2, 3, 4, 5); - Function> b = x -> tuple("bar", 2, 3, 4, 5, x + 1); + Tuple6 a = tuple("foo", 1, 2, 3, 4, 5); + Fn1> b = x -> tuple("bar", 2, 3, 4, 5, x + 1); assertEquals(tuple("foo", 1, 2, 3, 4, 6), a.flatMap(b)); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java index a62a36691..6203fe15e 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.adt.hlist; import com.jnape.palatable.lambda.adt.hlist.HList.HCons; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Before; @@ -12,8 +13,6 @@ import testsupport.traits.MonadLaws; import testsupport.traits.TraversableLaws; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.spy; @@ -32,7 +31,7 @@ public void setUp() { } @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) - public Tuple7 testSubject() { + public Tuple7 testSubject() { return tuple("one", 2, 3d, 4f, '5', (byte) 6, 7L); } @@ -65,8 +64,8 @@ public void accessors() { @Test public void randomAccess() { - Tuple6 spiedTail = spy(tuple("second", "third", "fourth", "fifth", "sixth", "seventh")); - Tuple7 tuple7 = new Tuple7<>("first", spiedTail); + Tuple6 spiedTail = spy(tuple("second", "third", "fourth", "fifth", "sixth", "seventh")); + Tuple7 tuple7 = new Tuple7<>("first", spiedTail); verify(spiedTail, times(1))._1(); verify(spiedTail, times(1))._2(); @@ -97,15 +96,17 @@ public void into() { @Test public void zipPrecedence() { - Tuple7 a = tuple("foo", 1, 2, 3, 4, 5, 6); - Tuple7> b = tuple("bar", 2, 3, 4, 5, 6, x -> x + 1); + Tuple7 a = + tuple("foo", 1, 2, 3, 4, 5, 6); + Tuple7> b = + tuple("bar", 2, 3, 4, 5, 6, x -> x + 1); assertEquals(tuple("bar", 2, 3, 4, 5, 6, 7), a.zip(b)); } @Test public void flatMapPrecedence() { - Tuple7 a = tuple("foo", 1, 2, 3, 4, 5, 6); - Function> b = x -> tuple("bar", 2, 3, 4, 5, 6, x + 1); + Tuple7 a = tuple("foo", 1, 2, 3, 4, 5, 6); + Fn1> b = x -> tuple("bar", 2, 3, 4, 5, 6, x + 1); assertEquals(tuple("foo", 1, 2, 3, 4, 5, 7), a.flatMap(b)); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java index c19ee8a58..6c788a83d 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.adt.hlist; import com.jnape.palatable.lambda.adt.hlist.HList.HCons; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Before; @@ -12,8 +13,6 @@ import testsupport.traits.MonadLaws; import testsupport.traits.TraversableLaws; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.spy; @@ -32,7 +31,7 @@ public void setUp() { } @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) - public Tuple8 testSubject() { + public Tuple8 testSubject() { return tuple("one", 2, 3d, 4f, '5', (byte) 6, 7L, (short) 65535); } @@ -66,8 +65,8 @@ public void accessors() { @Test public void randomAccess() { - Tuple7 spiedTail = spy(tuple("second", "third", "fourth", "fifth", "sixth", "seventh", "eighth")); - Tuple8 tuple8 = new Tuple8<>("first", spiedTail); + Tuple7 spiedTail = spy(tuple("second", "third", "fourth", "fifth", "sixth", "seventh", "eighth")); + Tuple8 tuple8 = new Tuple8<>("first", spiedTail); verify(spiedTail, times(1))._1(); verify(spiedTail, times(1))._2(); @@ -100,15 +99,19 @@ public void into() { @Test public void zipPrecedence() { - Tuple8 a = tuple("foo", 1, 2, 3, 4, 5, 6, 7); - Tuple8> b = tuple("bar", 2, 3, 4, 5, 6, 7, x -> x + 1); + Tuple8 a + = tuple("foo", 1, 2, 3, 4, 5, 6, 7); + Tuple8> b + = tuple("bar", 2, 3, 4, 5, 6, 7, x -> x + 1); assertEquals(tuple("bar", 2, 3, 4, 5, 6, 7, 8), a.zip(b)); } @Test public void flatMapPrecedence() { - Tuple8 a = tuple("foo", 1, 2, 3, 4, 5, 6, 7); - Function> b = x -> tuple("bar", 2, 3, 4, 5, 6, 7, x + 1); + Tuple8 a = + tuple("foo", 1, 2, 3, 4, 5, 6, 7); + Fn1> b = + x -> tuple("bar", 2, 3, 4, 5, 6, 7, x + 1); assertEquals(tuple("foo", 1, 2, 3, 4, 5, 6, 8), a.flatMap(b)); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hmap/HMapTest.java b/src/test/java/com/jnape/palatable/lambda/adt/hmap/HMapTest.java index 0c93ecb3f..f9e849f78 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hmap/HMapTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hmap/HMapTest.java @@ -13,7 +13,7 @@ import static com.jnape.palatable.lambda.adt.hmap.HMap.hMap; import static com.jnape.palatable.lambda.adt.hmap.HMap.singletonHMap; import static com.jnape.palatable.lambda.adt.hmap.TypeSafeKey.typeSafeKey; -import static com.jnape.palatable.lambda.lens.Iso.simpleIso; +import static com.jnape.palatable.lambda.optics.Iso.simpleIso; import static java.math.BigInteger.ONE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -156,11 +156,12 @@ public void demandForAbsentKey() { } @Test + @SuppressWarnings("serial") public void toMap() { TypeSafeKey stringKey = typeSafeKey(); TypeSafeKey intKey = typeSafeKey(); - assertEquals(new HashMap() {{ + assertEquals(new HashMap, Object>() {{ put(stringKey, "string"); put(intKey, 1); }}, hMap(stringKey, "string", @@ -263,7 +264,6 @@ public void convenienceStaticFactoryMethods() { } @Test - @SuppressWarnings("EqualsWithItself") public void equality() { assertEquals(emptyHMap(), emptyHMap()); diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hmap/SchemaTest.java b/src/test/java/com/jnape/palatable/lambda/adt/hmap/SchemaTest.java index 5d76e50cd..3fdbde74f 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hmap/SchemaTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hmap/SchemaTest.java @@ -9,7 +9,7 @@ import static com.jnape.palatable.lambda.adt.hmap.HMap.hMap; import static com.jnape.palatable.lambda.adt.hmap.Schema.schema; import static com.jnape.palatable.lambda.adt.hmap.TypeSafeKey.typeSafeKey; -import static com.jnape.palatable.lambda.lens.functions.View.view; +import static com.jnape.palatable.lambda.optics.functions.View.view; import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; import static testsupport.assertion.LensAssert.assertLensLawfulness; diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKeyTest.java b/src/test/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKeyTest.java index b9bb7e802..f03acea5b 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKeyTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKeyTest.java @@ -6,7 +6,7 @@ import static com.jnape.palatable.lambda.adt.hmap.HMap.emptyHMap; import static com.jnape.palatable.lambda.adt.hmap.TypeSafeKey.typeSafeKey; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; -import static com.jnape.palatable.lambda.lens.Iso.simpleIso; +import static com.jnape.palatable.lambda.optics.Iso.simpleIso; import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; diff --git a/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java b/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java index 9f5dabd60..0609643f5 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java @@ -1,16 +1,21 @@ package com.jnape.palatable.lambda.functions; import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.io.IO; import org.junit.Test; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; -import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.functions.Effect.effect; +import static com.jnape.palatable.lambda.functions.Effect.fromConsumer; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.specialized.SideEffect.sideEffect; +import static com.jnape.palatable.lambda.io.IO.io; import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; import static org.junit.Assert.assertEquals; public class EffectTest { @@ -19,33 +24,47 @@ public class EffectTest { public void covariantReturns() { List results = new ArrayList<>(); - Effect effect = results::add; - Effect diMapL = effect.diMapL(Object::toString); - Effect contraMap = effect.contraMap(Object::toString); - Effect compose = effect.compose(Object::toString); + Effect effect = fromConsumer(results::add); + Effect diMapL = effect.diMapL(Object::toString); + Effect contraMap = effect.contraMap(Object::toString); Effect stringEffect = effect.discardR(constantly("1")); - Effect andThen = effect.andThen(effect); - effect.accept("1"); - diMapL.accept("2"); - contraMap.accept("3"); - compose.accept("4"); - stringEffect.accept("5"); - andThen.accept("6"); + effect.apply("1").unsafePerformIO(); + diMapL.apply("2").unsafePerformIO(); + contraMap.apply("3").unsafePerformIO(); + stringEffect.apply("4").unsafePerformIO(); - assertEquals(asList("1", "2", "3", "4", "5", "6", "6"), results); + assertEquals(asList("1", "2", "3", "4"), results); + } + + @Test + public void andThen() { + AtomicInteger counter = new AtomicInteger(); + Effect inc = c -> io(sideEffect(c::incrementAndGet)); + + inc.andThen(inc).apply(counter).unsafePerformIO(); + assertEquals(2, counter.get()); } @Test public void staticFactoryMethods() { AtomicInteger counter = new AtomicInteger(); - Effect runnableEffect = effect(counter::incrementAndGet); - runnableEffect.apply(UNIT).unsafePerformIO(); + Effect sideEffect = effect(counter::incrementAndGet); + sideEffect.apply("foo").unsafePerformIO(); assertEquals(1, counter.get()); - Effect fnEffect = effect(AtomicInteger::incrementAndGet); + Effect fnEffect = Effect.fromConsumer(AtomicInteger::incrementAndGet); fnEffect.apply(counter).unsafePerformIO(); assertEquals(2, counter.get()); } + + @Test + public void toConsumer() { + @SuppressWarnings("RedundantTypeArguments") Effect> addFoo = l -> IO.io(() -> l.add("foo")); + Consumer> consumer = addFoo.toConsumer(); + ArrayList list = new ArrayList<>(); + consumer.accept(list); + assertEquals(singletonList("foo"), list); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/Fn0Test.java b/src/test/java/com/jnape/palatable/lambda/functions/Fn0Test.java index d04084205..87af14209 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/Fn0Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/Fn0Test.java @@ -1,21 +1,39 @@ package com.jnape.palatable.lambda.functions; -import com.jnape.palatable.traitor.annotations.TestTraits; -import com.jnape.palatable.traitor.runners.Traits; -import org.junit.runner.RunWith; -import testsupport.EqualityAwareFn0; -import testsupport.traits.ApplicativeLaws; -import testsupport.traits.FunctorLaws; -import testsupport.traits.MonadLaws; - -import static com.jnape.palatable.lambda.adt.Unit.UNIT; -import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; - -@RunWith(Traits.class) +import org.junit.Test; + +import java.util.concurrent.Callable; +import java.util.function.Supplier; + +import static org.junit.Assert.assertEquals; + public class Fn0Test { - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) - public Fn0 testSubject() { - return new EqualityAwareFn0<>(constantly(1).thunk(UNIT)); + @Test + public void fromSupplier() { + Supplier supplier = () -> 1; + Fn0 fn0 = Fn0.fromSupplier(supplier); + assertEquals((Integer) 1, fn0.apply()); + } + + @Test + public void fromCallable() { + Callable callable = () -> 1; + Fn0 fn0 = Fn0.fromCallable(callable); + assertEquals((Integer) 1, fn0.apply()); + } + + @Test + public void toSupplier() { + Fn0 fn0 = () -> 1; + Supplier supplier = fn0.toSupplier(); + assertEquals((Integer) 1, supplier.get()); + } + + @Test + public void toCallable() throws Exception { + Fn0 fn0 = () -> 1; + Callable callable = fn0.toCallable(); + assertEquals((Integer) 1, callable.call()); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java b/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java index bd3237f2c..85db3d418 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java @@ -4,7 +4,7 @@ import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; import org.junit.runner.RunWith; -import testsupport.EqualityAwareFn1; +import testsupport.EquatableM; import testsupport.traits.ApplicativeLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; @@ -12,7 +12,11 @@ import java.util.function.Function; import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.adt.choice.Choice2.a; +import static com.jnape.palatable.lambda.adt.choice.Choice2.b; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.Fn1.fn1; +import static com.jnape.palatable.lambda.functions.Fn1.fromFunction; import static com.jnape.palatable.lambda.functions.builtin.fn2.ReduceLeft.reduceLeft; import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; @@ -21,8 +25,8 @@ public class Fn1Test { @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) - public Fn1 testSubject() { - return new EqualityAwareFn1<>("1", Integer::parseInt); + public EquatableM, ?> testSubject() { + return new EquatableM<>(fn1(Integer::parseInt), f -> f.apply("1")); } @Test @@ -35,9 +39,11 @@ public void profunctorProperties() { } @Test - public void fn1() { - Function parseInt = Integer::parseInt; - assertEquals((Integer) 1, Fn1.fn1(parseInt).apply("1")); + public void staticFactoryMethod() { + assertEquals((Integer) 1, Fn1.fn1(Integer::parseInt).apply("1")); + Function function = Integer::parseInt; + Fn1 fn1 = fromFunction(function); + assertEquals((Integer) 1, fn1.apply("1")); } @Test @@ -49,13 +55,13 @@ public void thunk() { @Test public void widen() { Fn1 addOne = x -> x + 1; - assertEquals(just(4), reduceLeft(addOne.widen().toBiFunction(), asList(1, 2, 3))); + assertEquals(just(4), reduceLeft(addOne.widen(), asList(1, 2, 3))); } @Test - public void strengthen() { + public void cartesian() { Fn1 add1 = x -> x + 1; - assertEquals(tuple("a", 2), add1.strengthen().apply(tuple("a", 1))); + assertEquals(tuple("a", 2), add1.cartesian().apply(tuple("a", 1))); } @Test @@ -63,4 +69,25 @@ public void carry() { Fn1 add1 = x -> x + 1; assertEquals(tuple(1, 2), add1.carry().apply(1)); } + + @Test + public void cocartesian() { + Fn1 add1 = x -> x + 1; + assertEquals(a("foo"), add1.cocartesian().apply(a("foo"))); + assertEquals(b(2), add1.cocartesian().apply(b(1))); + } + + @Test + public void choose() { + Fn1 add1 = Integer::parseInt; + assertEquals(b(123), add1.choose().apply("123")); + assertEquals(a("foo"), add1.choose().apply("foo")); + } + + @Test + public void toFunction() { + Fn1 add1 = x -> x + 1; + Function function = add1.toFunction(); + assertEquals((Integer) 2, function.apply(1)); + } } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/Fn2Test.java b/src/test/java/com/jnape/palatable/lambda/functions/Fn2Test.java index 89cf70a03..71e3a65e3 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/Fn2Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/Fn2Test.java @@ -8,7 +8,6 @@ import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; public class Fn2Test { @@ -30,24 +29,27 @@ public void uncurries() { assertThat(CHECK_LENGTH.uncurry().apply(tuple("abc", 3)), is(true)); } - @Test - @SuppressWarnings("ConstantConditions") - public void composePreservesTypeSpecificity() { - assertTrue(CHECK_LENGTH.compose(Object::toString) instanceof Fn2); - } - @Test public void toBiFunction() { BiFunction biFunction = CHECK_LENGTH.toBiFunction(); assertEquals(true, biFunction.apply("abc", 3)); } + @Test + public void curried() { + Fn1> curriedFn1 = (x) -> (y) -> String.format(x, y); + assertEquals("foo bar", Fn2.curried(curriedFn1).apply("foo %s", "bar")); + } + @Test public void fn2() { - BiFunction biFunction = String::format; - assertEquals("foo bar", Fn2.fn2(biFunction).apply("foo %s", "bar")); + Fn2 fn2 = Fn2.fn2(String::format); + assertEquals("foo bar", fn2.apply("foo %s", "bar")); + } - Fn1> curriedFn1 = (x) -> (y) -> String.format(x, y); - assertEquals("foo bar", Fn2.fn2(curriedFn1).apply("foo %s", "bar")); + @Test + public void fromBiFunction() { + BiFunction biFunction = String::format; + assertEquals("foo bar", Fn2.fromBiFunction(biFunction).apply("foo %s", "bar")); } } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/IOTest.java b/src/test/java/com/jnape/palatable/lambda/functions/IOTest.java deleted file mode 100644 index cab2595c0..000000000 --- a/src/test/java/com/jnape/palatable/lambda/functions/IOTest.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.jnape.palatable.lambda.functions; - -import com.jnape.palatable.lambda.adt.hlist.Tuple2; -import com.jnape.palatable.traitor.annotations.TestTraits; -import com.jnape.palatable.traitor.runners.Traits; -import org.junit.Test; -import org.junit.runner.RunWith; -import testsupport.EqualityAwareIO; -import testsupport.traits.ApplicativeLaws; -import testsupport.traits.FunctorLaws; -import testsupport.traits.MonadLaws; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.function.Function; - -import static com.jnape.palatable.lambda.adt.Unit.UNIT; -import static com.jnape.palatable.lambda.functions.Fn0.fn0; -import static com.jnape.palatable.lambda.functions.IO.externallyManaged; -import static com.jnape.palatable.lambda.functions.IO.io; -import static com.jnape.palatable.lambda.functions.builtin.fn2.Tupler2.tupler; -import static com.jnape.palatable.lambda.functions.specialized.checked.CheckedFn1.checked; -import static java.util.concurrent.CompletableFuture.completedFuture; -import static java.util.concurrent.Executors.newFixedThreadPool; -import static java.util.concurrent.ForkJoinPool.commonPool; -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()); - } - - @Test(timeout = 100) - public void unsafePerformAsyncIOWithoutExecutor() { - assertEquals((Integer) 1, io(() -> 1).unsafePerformAsyncIO().join()); - } - - @Test(timeout = 100) - public void unsafePerformAsyncIOWithExecutor() { - assertEquals((Integer) 1, io(() -> 1).unsafePerformAsyncIO(newFixedThreadPool(1)).join()); - } - - @Test - public void zipAndDerivativesComposesInParallel() { - String a = "foo"; - Fn1> f = tupler(1); - - ExecutorService executor = newFixedThreadPool(2); - CountDownLatch advanceFirst = new CountDownLatch(1); - CountDownLatch advanceSecond = new CountDownLatch(1); - - IO ioA = io(checked(__ -> { - advanceFirst.countDown(); - advanceSecond.await(); - return a; - })); - IO>> ioF = io(checked(__ -> { - advanceFirst.await(); - advanceSecond.countDown(); - return f; - })); - - IO> zip = ioA.zip(ioF); - assertEquals(f.apply(a), zip.unsafePerformAsyncIO().join()); - assertEquals(f.apply(a), zip.unsafePerformAsyncIO(executor).join()); - assertEquals(f.apply(a), zip.unsafePerformAsyncIO(executor).join()); - - IO>> discardL = ioA.discardL(ioF); - assertEquals(f, discardL.unsafePerformAsyncIO().join()); - assertEquals(f, discardL.unsafePerformAsyncIO(executor).join()); - - IO discardR = ioA.discardR(ioF); - assertEquals(a, discardR.unsafePerformAsyncIO().join()); - assertEquals(a, discardR.unsafePerformAsyncIO(executor).join()); - } - - @Test - public void delegatesToExternallyManagedFuture() { - CompletableFuture future = completedFuture(1); - IO io = externallyManaged(() -> future); - assertEquals((Integer) 1, io.unsafePerformIO()); - assertEquals((Integer) 1, io.unsafePerformAsyncIO().join()); - assertEquals((Integer) 1, io.unsafePerformAsyncIO(commonPool()).join()); - } - - @Test - public void exceptionallyRecoversThrowableToResult() { - IO io = io(() -> { throw new UnsupportedOperationException("foo"); }); - assertEquals("foo", io.exceptionally(Throwable::getMessage).unsafePerformIO()); - - IO externallyManaged = externallyManaged(() -> new CompletableFuture() {{ - completeExceptionally(new UnsupportedOperationException("foo")); - }}).exceptionally(e -> e.getCause().getMessage()); - assertEquals("foo", externallyManaged.unsafePerformIO()); - } - - @Test - public void exceptionallyRescuesFutures() { - ExecutorService executor = newFixedThreadPool(2); - - IO io = io(() -> { throw new UnsupportedOperationException("foo"); }); - assertEquals("foo", io.exceptionally(e -> e.getCause().getMessage()).unsafePerformAsyncIO().join()); - assertEquals("foo", io.exceptionally(e -> e.getCause().getMessage()).unsafePerformAsyncIO(executor).join()); - - IO externallyManaged = externallyManaged(() -> new CompletableFuture() {{ - completeExceptionally(new UnsupportedOperationException("foo")); - }}).exceptionally(e -> e.getCause().getMessage()); - assertEquals("foo", externallyManaged.unsafePerformIO()); - - } -} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/CycleTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/CycleTest.java index f9acf8d22..d9c04a459 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/CycleTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/CycleTest.java @@ -17,7 +17,7 @@ public class CycleTest { @TestTraits({Laziness.class, ImmutableIteration.class, InfiniteIteration.class}) - public Cycle createTestSubject() { + public Cycle createTestSubject() { return cycle(); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/DistinctTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/DistinctTest.java index 4755af103..b535e381c 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/DistinctTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/DistinctTest.java @@ -19,7 +19,7 @@ public class DistinctTest { @TestTraits({Laziness.class, InfiniteIterableSupport.class, EmptyIterableSupport.class, FiniteIteration.class, ImmutableIteration.class}) - public Distinct testSubject() { + public Distinct testSubject() { return distinct(); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/DowncastTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/DowncastTest.java new file mode 100644 index 000000000..b21e30b73 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/DowncastTest.java @@ -0,0 +1,28 @@ +package com.jnape.palatable.lambda.functions.builtin.fn1; + +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.functor.Functor; +import org.junit.Test; + +import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Downcast.downcast; + +public class DowncastTest { + + @Test + @SuppressWarnings("unused") + public void safeDowncast() { + CharSequence charSequence = "123"; + String s = downcast(charSequence); + + Functor> maybeInt = nothing(); + Maybe cast = downcast(maybeInt); + } + + @Test(expected = ClassCastException.class) + @SuppressWarnings({"JavacQuirks", "unused"}) + public void unsafeDowncast() { + CharSequence charSequence = "123"; + Integer explosion = downcast(charSequence); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/FlattenTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/FlattenTest.java index d1889525b..8138aaed0 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/FlattenTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/FlattenTest.java @@ -28,7 +28,7 @@ public class FlattenTest { @TestTraits({Laziness.class, InfiniteIterableSupport.class, EmptyIterableSupport.class, FiniteIteration.class}) public Fn1, Iterable> testSubject() { - return Flatten.flatten().compose(Map.>map(Collections::singletonList)); + return Flatten.flatten().contraMap(Map.>map(Collections::singletonList)); } @Test diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/InitTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/InitTest.java index dde20b9fe..b27b65903 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/InitTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/InitTest.java @@ -23,7 +23,7 @@ public class InitTest { @TestTraits({EmptyIterableSupport.class, InfiniteIterableSupport.class, Laziness.class, ImmutableIteration.class, FiniteIteration.class}) - public Fn1 testSubject() { + public Fn1, ? extends Iterable> testSubject() { return init(); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/InitsTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/InitsTest.java index 191425e2c..50b417d58 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/InitsTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/InitsTest.java @@ -22,7 +22,7 @@ public class InitsTest { @TestTraits({Laziness.class, EmptyIterableSupport.class, InfiniteIterableSupport.class, FiniteIteration.class, ImmutableIteration.class}) - public Fn1 testSubject() { + public Fn1, ? extends Iterable> testSubject() { return inits(); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/OccurrencesTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/OccurrencesTest.java index bb11d5782..290fa2736 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/OccurrencesTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/OccurrencesTest.java @@ -2,17 +2,18 @@ import org.junit.Test; +import java.util.Collections; import java.util.HashMap; import static com.jnape.palatable.lambda.functions.builtin.fn1.Occurrences.occurrences; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; -import static java.util.Collections.emptyMap; import static org.junit.Assert.assertEquals; public class OccurrencesTest { @Test + @SuppressWarnings("serial") public void occurrencesOfIndividualElements() { assertEquals(new HashMap() {{ put("foo", 2L); @@ -23,6 +24,6 @@ public void occurrencesOfIndividualElements() { @Test public void emptyIterableHasNoOccurrences() { - assertEquals(emptyMap(), occurrences(emptyList())); + assertEquals(Collections.emptyMap(), occurrences(emptyList())); } } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/RepeatTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/RepeatTest.java index 80112707f..de34c53b4 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/RepeatTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/RepeatTest.java @@ -17,7 +17,7 @@ public class RepeatTest { @TestTraits({Laziness.class, ImmutableIteration.class, InfiniteIteration.class}) - public Repeat createTestSubject() { + public Repeat createTestSubject() { return repeat(); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/ReverseTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/ReverseTest.java index 308b9123e..434ed4ba2 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/ReverseTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/ReverseTest.java @@ -24,7 +24,7 @@ public class ReverseTest { @TestTraits({Laziness.class, ImmutableIteration.class, FiniteIteration.class, EmptyIterableSupport.class}) - public Reverse createTestSubject() { + public Reverse createTestSubject() { return reverse(); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/SizeTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/SizeTest.java index 7ee079443..a0039dc3e 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/SizeTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/SizeTest.java @@ -21,6 +21,7 @@ public void countsElementsInIterable() { } @Test + @SuppressWarnings("serial") public void optimizesForCollections() { Collection collection = spy(new ArrayList() {{ add(1); diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/TailTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/TailTest.java index 055cd9c9b..57a854456 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/TailTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/TailTest.java @@ -20,7 +20,7 @@ public class TailTest { @TestTraits({Laziness.class, EmptyIterableSupport.class, FiniteIteration.class, ImmutableIteration.class}) - public Fn1 createTraitsTestSubject() { + public Fn1, ?> createTraitsTestSubject() { return tail(); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/TailsTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/TailsTest.java index 45b3a1b25..a384d21cc 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/TailsTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/TailsTest.java @@ -27,7 +27,7 @@ public class TailsTest { @TestTraits({EmptyIterableSupport.class, InfiniteIterableSupport.class, FiniteIteration.class, ImmutableIteration.class, Laziness.class}) - public Fn1 testSubject() { + public Fn1, ? extends Iterable> testSubject() { return tails(); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/UnconsTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/UnconsTest.java index b3c8ece22..115ba8164 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/UnconsTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/UnconsTest.java @@ -19,7 +19,7 @@ public class UnconsTest { @TestTraits({EmptyIterableSupport.class}) - public Uncons testSubject() { + public Uncons testSubject() { return uncons(); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AllTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AllTest.java index c266a4bfb..376295e5b 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AllTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AllTest.java @@ -7,8 +7,6 @@ import org.junit.runner.RunWith; import testsupport.traits.EmptyIterableSupport; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat; import static com.jnape.palatable.lambda.functions.builtin.fn2.All.all; @@ -19,7 +17,7 @@ @RunWith(Traits.class) public class AllTest { - private static final Function EVEN = x -> x.doubleValue() % 2 == 0; + private static final Fn1 EVEN = x -> x.doubleValue() % 2 == 0; @TestTraits({EmptyIterableSupport.class}) public Fn1, ? extends Boolean> createTestSubject() { diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AlterTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AlterTest.java index 73e11e800..9bff92fa4 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AlterTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AlterTest.java @@ -4,6 +4,7 @@ import java.util.ArrayList; +import static com.jnape.palatable.lambda.functions.Effect.fromConsumer; import static com.jnape.palatable.lambda.functions.builtin.fn2.Alter.alter; import static java.util.Collections.singletonList; import static org.junit.Assert.assertEquals; @@ -14,7 +15,7 @@ public class AlterTest { @Test public void altersInput() { ArrayList input = new ArrayList<>(); - assertSame(input, alter(xs -> xs.add("foo"), input).unsafePerformIO()); + assertSame(input, alter(fromConsumer(xs -> xs.add("foo")), input).unsafePerformIO()); assertEquals(singletonList("foo"), input); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AnyTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AnyTest.java index ff632730b..ccf0451cd 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AnyTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AnyTest.java @@ -7,8 +7,6 @@ import org.junit.runner.RunWith; import testsupport.traits.EmptyIterableSupport; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat; import static com.jnape.palatable.lambda.functions.builtin.fn2.Any.any; @@ -19,7 +17,7 @@ @RunWith(Traits.class) public class AnyTest { - public static final Function EVEN = x -> x % 2 == 0; + public static final Fn1 EVEN = x -> x % 2 == 0; @TestTraits({EmptyIterableSupport.class}) public Fn1, Boolean> createTestSubject() { diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/FilterTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/FilterTest.java index 27e5fa0bd..73ca133bc 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/FilterTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/FilterTest.java @@ -25,7 +25,7 @@ public class FilterTest { @TestTraits({Laziness.class, EmptyIterableSupport.class, FiniteIteration.class, ImmutableIteration.class}) - public Fn1 testSubject() { + public Fn1, ?> testSubject() { return filter(constantly(true)); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupByTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupByTest.java index 02f8e8bf2..5a9401099 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupByTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupByTest.java @@ -2,6 +2,7 @@ import org.junit.Test; +import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -9,10 +10,10 @@ import static com.jnape.palatable.lambda.functions.builtin.fn2.GroupBy.groupBy; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; -import static java.util.Collections.emptyMap; import static java.util.Collections.singletonList; import static org.junit.Assert.assertEquals; +@SuppressWarnings("serial") public class GroupByTest { @Test @@ -25,6 +26,6 @@ public void grouping() { @Test public void emptyIterableProducesEmptyMap() { - assertEquals(emptyMap(), groupBy(id(), emptyList())); + assertEquals(Collections.>emptyMap(), groupBy(id(), emptyList())); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/IterateTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/IterateTest.java index 961aa0d15..564290452 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/IterateTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/IterateTest.java @@ -21,7 +21,7 @@ public class IterateTest { @TestTraits({Laziness.class, InfiniteIteration.class, ImmutableIteration.class}) - public Fn1 createTestSubject() { + public Fn1, ? extends Iterable> createTestSubject() { return iterate(constantly(new ArrayList<>())); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRecTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRecTest.java new file mode 100644 index 000000000..8987fe32a --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRecTest.java @@ -0,0 +1,37 @@ +package com.jnape.palatable.lambda.functions.builtin.fn2; + +import org.junit.Test; + +import java.util.concurrent.atomic.AtomicBoolean; + +import static com.jnape.palatable.lambda.functions.builtin.fn2.LazyRec.lazyRec; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static testsupport.Constants.STACK_EXPLODING_NUMBER; + +public class LazyRecTest { + + @Test + public void recursivelyComputesValue() { + assertEquals(STACK_EXPLODING_NUMBER, + LazyRec.lazyRec((f, x) -> x < STACK_EXPLODING_NUMBER + ? f.apply(x + 1) + : lazy(x), + 0) + .value()); + } + + @Test + public void defersAllComputationUntilForced() { + AtomicBoolean invoked = new AtomicBoolean(false); + lazyRec((f, x) -> { + invoked.set(true); + return lazy(x); + }, + 0); + + assertFalse(invoked.get()); + } + +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/MagnetizeByTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/MagnetizeByTest.java index 1995332f2..25b0723eb 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/MagnetizeByTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/MagnetizeByTest.java @@ -11,11 +11,10 @@ import testsupport.traits.InfiniteIterableSupport; import testsupport.traits.Laziness; -import java.util.function.BiFunction; - import static com.jnape.palatable.lambda.functions.builtin.fn1.Last.last; import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat; import static com.jnape.palatable.lambda.functions.builtin.fn2.Eq.eq; +import static com.jnape.palatable.lambda.functions.builtin.fn2.GTE.gte; import static com.jnape.palatable.lambda.functions.builtin.fn2.MagnetizeBy.magnetizeBy; import static com.jnape.palatable.lambda.functions.builtin.fn2.Take.take; import static java.util.Arrays.asList; @@ -31,16 +30,15 @@ public class MagnetizeByTest { @TestTraits({EmptyIterableSupport.class, InfiniteIterableSupport.class, FiniteIteration.class, ImmutableIteration.class, Laziness.class}) public Fn1, Iterable>> testSubject() { - return magnetizeBy(eq().toBiFunction()); + return magnetizeBy(eq()); } @Test @SuppressWarnings("unchecked") public void magnetizesElementsByPredicateOutcome() { - BiFunction lte = (x, y) -> x <= y; - assertThat(magnetizeBy(lte, emptyList()), isEmpty()); - assertThat(magnetizeBy(lte, singletonList(1)), contains(iterates(1))); - assertThat(magnetizeBy(lte, asList(1, 2, 3, 2, 2, 3, 2, 1)), + assertThat(magnetizeBy(GTE.gte(), emptyList()), isEmpty()); + assertThat(magnetizeBy(gte(), singletonList(1)), contains(iterates(1))); + assertThat(magnetizeBy(gte(), asList(1, 2, 3, 2, 2, 3, 2, 1)), contains(iterates(1, 2, 3), iterates(2, 2, 3), iterates(2), diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/MapTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/MapTest.java index 92a6e725b..4e7f8967c 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/MapTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/MapTest.java @@ -21,7 +21,7 @@ public class MapTest { @TestTraits({Laziness.class, EmptyIterableSupport.class, InfiniteIterableSupport.class, FiniteIteration.class, ImmutableIteration.class}) - public Fn1 createTraitsTestSubject() { + public Fn1, ?> createTraitsTestSubject() { return map(id()); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial2Test.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial2Test.java deleted file mode 100644 index 81598f331..000000000 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial2Test.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.jnape.palatable.lambda.functions.builtin.fn2; - -import org.junit.Test; - -import java.util.function.BiFunction; - -import static com.jnape.palatable.lambda.functions.builtin.fn2.Partial2.partial2; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; - -public class Partial2Test { - - @Test - public void partiallyAppliesFunction() { - BiFunction subtract = (minuend, subtrahend) -> minuend - subtrahend; - assertThat(partial2(subtract, 3).apply(2), is(1)); - } -} diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial3Test.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial3Test.java deleted file mode 100644 index f939c68eb..000000000 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial3Test.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.jnape.palatable.lambda.functions.builtin.fn2; - -import com.jnape.palatable.lambda.functions.Fn3; -import org.junit.Test; - -import static com.jnape.palatable.lambda.functions.builtin.fn2.Partial3.partial3; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; - -public class Partial3Test { - - @Test - public void partiallyAppliesFunction() { - Fn3 concat = (s1, s2, s3) -> s1 + s2 + s3; - - assertThat(partial3(concat, "foo").apply(" bar", " baz"), is("foo bar baz")); - } -} diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/PartitionTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/PartitionTest.java index 05366dfb4..ed75f2568 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/PartitionTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/PartitionTest.java @@ -29,9 +29,9 @@ public class PartitionTest { @TestTraits({Laziness.class, EmptyIterableSupport.class, FiniteIteration.class, ImmutableIteration.class}) - public Subjects> createTraitsTestSubject() { - return subjects(partition(constantly(a(1))).andThen(Tuple2::_1), - partition(constantly(b(1))).andThen(Tuple2::_2)); + public Subjects, ?>> createTraitsTestSubject() { + return subjects(partition(constantly(a(1))).fmap(Tuple2::_1), + partition(constantly(b(1))).fmap(Tuple2::_2)); } @Test diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2Test.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2Test.java index af16097b3..3b0860b22 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2Test.java @@ -8,6 +8,7 @@ import static com.jnape.palatable.lambda.adt.Either.right; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.Effect.fromConsumer; import static com.jnape.palatable.lambda.functions.builtin.fn2.Peek2.peek2; import static org.junit.Assert.assertEquals; @@ -15,17 +16,18 @@ public class Peek2Test { @Test public void peeksAtBothBifunctorValues() { - AtomicInteger counter = new AtomicInteger(0); - Tuple2 tuple = tuple(1, 2); - assertEquals(tuple, peek2(__ -> counter.incrementAndGet(), __ -> counter.incrementAndGet(), tuple)); + AtomicInteger counter = new AtomicInteger(0); + Tuple2 tuple = tuple(1, 2); + assertEquals(tuple, peek2(fromConsumer(__ -> counter.incrementAndGet()), + fromConsumer(__ -> counter.incrementAndGet()), tuple)); assertEquals(2, counter.get()); } @Test public void followsSameConventionsAsBimap() { - AtomicInteger counter = new AtomicInteger(0); - Either either = right(1); - peek2(__ -> counter.incrementAndGet(), __ -> counter.incrementAndGet(), either); + AtomicInteger counter = new AtomicInteger(0); + Either either = right(1); + peek2(fromConsumer(__ -> counter.incrementAndGet()), fromConsumer(__ -> counter.incrementAndGet()), either); assertEquals(1, counter.get()); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/PeekTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/PeekTest.java index 337899584..5ab1fba4f 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/PeekTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/PeekTest.java @@ -6,6 +6,7 @@ import java.util.concurrent.atomic.AtomicInteger; import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.functions.Effect.fromConsumer; import static com.jnape.palatable.lambda.functions.builtin.fn2.Peek.peek; import static org.junit.Assert.assertEquals; @@ -13,9 +14,9 @@ public class PeekTest { @Test public void appliesConsumerToCarrierValue() { - AtomicInteger counter = new AtomicInteger(0); + AtomicInteger counter = new AtomicInteger(0); Maybe maybeString = just("foo"); - assertEquals(maybeString, peek(x -> counter.incrementAndGet(), maybeString)); + assertEquals(maybeString, peek(fromConsumer(x -> counter.incrementAndGet()), maybeString)); assertEquals(1, counter.get()); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SequenceTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SequenceTest.java index e51dfbaa1..cec572406 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SequenceTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SequenceTest.java @@ -2,11 +2,12 @@ import com.jnape.palatable.lambda.adt.Either; import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.builtin.Compose; import com.jnape.palatable.lambda.functor.builtin.Identity; import org.junit.Test; -import java.util.function.Function; +import java.util.Map; import static com.jnape.palatable.lambda.adt.Either.right; import static com.jnape.palatable.lambda.adt.Maybe.just; @@ -22,8 +23,8 @@ public class SequenceTest { @Test public void naturality() { - Function, Either> t = id -> right(id.runIdentity()); - Either> traversable = right(new Identity<>(1)); + Fn1, Either> t = id -> right(id.runIdentity()); + Either> traversable = right(new Identity<>(1)); assertEquals(t.apply(sequence(traversable, Identity::new).fmap(id())), sequence(traversable.fmap(t), Either::right)); @@ -69,5 +70,8 @@ public void compilation() { Maybe> d = sequence(asList(just(1), just(2)), Maybe::just); assertThat(d.orElseThrow(AssertionError::new), iterates(1, 2)); + + Either> e = sequence(singletonMap("foo", right(1)), Either::right); + assertEquals(right(singletonMap("foo", 1)), e); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToCollectionTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToCollectionTest.java index 584dd876d..6188c6765 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToCollectionTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToCollectionTest.java @@ -3,8 +3,6 @@ import org.junit.Test; import java.util.ArrayList; -import java.util.Collection; -import java.util.function.Supplier; import static com.jnape.palatable.lambda.functions.builtin.fn2.ToCollection.toCollection; import static java.util.Arrays.asList; @@ -14,7 +12,6 @@ public class ToCollectionTest { @Test public void convertsIterablesToCollectionInstance() { - Supplier> listFactory = ArrayList::new; - assertEquals(asList(1, 2, 3), toCollection(listFactory, asList(1, 2, 3))); + assertEquals(asList(1, 2, 3), toCollection(ArrayList::new, asList(1, 2, 3))); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToMapTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToMapTest.java index 21ab43c8d..2573212f6 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToMapTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToMapTest.java @@ -13,6 +13,7 @@ public class ToMapTest { @Test + @SuppressWarnings("serial") public void collectsEntriesIntoMap() { Map expected = new HashMap() {{ put("foo", 1); diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/UnfoldrTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/UnfoldrTest.java index 95b0cf7c1..4c876912b 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/UnfoldrTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/UnfoldrTest.java @@ -23,7 +23,7 @@ public class UnfoldrTest { @TestTraits({Laziness.class, InfiniteIteration.class, ImmutableIteration.class}) - public Fn1 createTestSubject() { + public Fn1, ? extends Iterable> createTestSubject() { return unfoldr(x -> just(tuple(x, x))); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/BracketTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/BracketTest.java new file mode 100644 index 000000000..389ca5508 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/BracketTest.java @@ -0,0 +1,77 @@ +package com.jnape.palatable.lambda.functions.builtin.fn3; + +import com.jnape.palatable.lambda.io.IO; +import org.junit.Before; +import org.junit.Test; + +import java.util.concurrent.atomic.AtomicInteger; + +import static com.jnape.palatable.lambda.functions.builtin.fn3.Bracket.bracket; +import static com.jnape.palatable.lambda.io.IO.io; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +public class BracketTest { + + private AtomicInteger count; + + @Before + public void setUp() { + count = new AtomicInteger(0); + } + + @Test + public void cleanupHappyPath() { + IO hashIO = bracket(io(() -> count), c -> io(c::incrementAndGet), c -> io(c::hashCode)); + + assertEquals(0, count.get()); + assertEquals((Integer) count.hashCode(), hashIO.unsafePerformIO()); + assertEquals(1, count.get()); + } + + @Test + public void cleanupSadPath() { + IllegalStateException thrown = new IllegalStateException("kaboom"); + IO hashIO = bracket(io(count), c -> io(c::incrementAndGet), c -> io(() -> {throw thrown;})); + + try { + hashIO.unsafePerformIO(); + fail("Expected exception to be raised"); + } catch (IllegalStateException actual) { + assertEquals(thrown, actual); + assertEquals(1, count.get()); + } + } + + @Test + public void cleanupOnlyRunsIfInitialIORuns() { + IllegalStateException thrown = new IllegalStateException("kaboom"); + IO hashIO = bracket(io(() -> {throw thrown;}), + __ -> io(count::incrementAndGet), + __ -> io(count::incrementAndGet)); + try { + hashIO.unsafePerformIO(); + fail("Expected exception to be raised"); + } catch (IllegalStateException actual) { + assertEquals(thrown, actual); + assertEquals(0, count.get()); + } + } + + @Test + public void errorsInCleanupAreAddedToBodyErrors() { + IllegalStateException bodyError = new IllegalStateException("kaboom"); + IllegalStateException cleanupError = new IllegalStateException("KABOOM"); + IO hashIO = bracket(io(count), + c -> io(() -> {throw cleanupError;}), + c -> io(() -> {throw bodyError;})); + try { + hashIO.unsafePerformIO(); + fail("Expected exception to be raised"); + } catch (IllegalStateException actual) { + assertEquals(bodyError, actual); + assertArrayEquals(new Throwable[]{cleanupError}, actual.getSuppressed()); + } + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldRightTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldRightTest.java index b40915da7..912ee9b4a 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldRightTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldRightTest.java @@ -1,17 +1,22 @@ package com.jnape.palatable.lambda.functions.builtin.fn3; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; import org.junit.runner.RunWith; import testsupport.traits.EmptyIterableSupport; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Iterate.iterate; import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldRight.foldRight; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; +import static testsupport.Constants.STACK_EXPLODING_NUMBER; import static testsupport.functions.ExplainFold.explainFold; @RunWith(Traits.class) @@ -19,14 +24,25 @@ public class FoldRightTest { @TestTraits({EmptyIterableSupport.class}) public Fn1, Iterable> createTestSubject() { - return foldRight((o, objects) -> objects, singletonList(new Object())); + return foldRight((o, objects) -> objects, lazy(singletonList(new Object()))).fmap(Lazy::value); } @Test public void foldRightAccumulatesRightToLeft() { - assertThat( - foldRight(explainFold(), "5", asList("1", "2", "3", "4")), - is("(1 + (2 + (3 + (4 + 5))))") + assertThat(foldRight((a, lazyB) -> lazyB.fmap(b -> explainFold().apply(a, b)), + lazy("5"), + asList("1", "2", "3", "4")) + .value(), + is("(1 + (2 + (3 + (4 + 5))))") ); } + + @Test + public void stackSafe() { + Lazy lazy = foldRight((x, lazyY) -> x < STACK_EXPLODING_NUMBER ? lazyY.fmap(y -> y) : lazy(x), + lazy(0), + iterate(x -> x + 1, 0)); + + assertEquals(STACK_EXPLODING_NUMBER, lazy.value()); + } } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2Test.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2Test.java index 1e575879d..f775e60ec 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2Test.java @@ -2,10 +2,9 @@ import com.jnape.palatable.lambda.adt.Either; import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.functions.Fn2; import org.junit.Test; -import java.util.function.BiFunction; - import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.Either.right; import static com.jnape.palatable.lambda.adt.Maybe.just; @@ -17,7 +16,7 @@ public class LiftA2Test { @Test public void inference() { - BiFunction add = (x, y) -> x + y; + Fn2 add = Integer::sum; Maybe a = liftA2(add, just(1), just(2)); assertEquals(just(3), a); @@ -31,7 +30,7 @@ public void inference() { Maybe d = liftA2(add, nothing(), nothing()); assertEquals(nothing(), d); - Either e = liftA2(add, Either.right(1), right(2)); + Either e = liftA2(add, Either.right(1), right(2)); assertEquals(right(3), e); Either f = liftA2(add, left("error"), right(2)); diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/ZipWithTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/ZipWithTest.java index ee1408417..034fe1b9a 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/ZipWithTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/ZipWithTest.java @@ -10,8 +10,6 @@ import testsupport.traits.ImmutableIteration; import testsupport.traits.Laziness; -import java.util.function.BiFunction; - import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static com.jnape.palatable.lambda.functions.builtin.fn2.Zip.zip; import static com.jnape.palatable.lambda.functions.builtin.fn3.ZipWith.zipWith; @@ -30,18 +28,16 @@ public Fn1, Iterable> createTestSubject() { @Test public void zipsTwoIterablesTogetherWithFunction() { Iterable oneThroughFive = asList(1, 2, 3, 4, 5); - Iterable sixThroughTen = asList(6, 7, 8, 9, 10); + Iterable sixThroughTen = asList(6, 7, 8, 9, 10); - BiFunction add = (a, b) -> a + b; - Iterable sums = ZipWith.zipWith(add, oneThroughFive, sixThroughTen); + Iterable sums = zipWith(Integer::sum, oneThroughFive, sixThroughTen); assertThat(sums, iterates(7, 9, 11, 13, 15)); } @Test - @SuppressWarnings("unchecked") public void zipsAsymmetricallySizedIterables() { - Iterable men = asList("Jack", "Sonny"); + Iterable men = asList("Jack", "Sonny"); Iterable women = asList("Jill", "Cher", "Madonna"); Iterable> couples = zip(men, women); diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimitTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimitTest.java index 0459a8be1..b91b92b08 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimitTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimitTest.java @@ -1,8 +1,7 @@ package com.jnape.palatable.lambda.functions.builtin.fn4; -import com.jnape.palatable.lambda.adt.Try; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.iteration.IterationInterruptedException; +import com.jnape.palatable.lambda.internal.iteration.IterationInterruptedException; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Before; @@ -17,8 +16,10 @@ import java.time.Duration; import java.util.concurrent.CountDownLatch; +import static com.jnape.palatable.lambda.adt.Try.trying; import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat; import static com.jnape.palatable.lambda.functions.builtin.fn4.RateLimit.rateLimit; +import static com.jnape.palatable.lambda.functions.specialized.SideEffect.sideEffect; import static java.time.Clock.systemUTC; import static java.time.Duration.ZERO; import static java.util.Arrays.asList; @@ -55,18 +56,17 @@ public void zeroDurationJustIteratesElements() { @Test public void limitPerDurationIsHonoredAccordingToClock() { Duration duration = Duration.ofMillis(10); - long limit = 2L; + long limit = 2L; assertThat(rateLimit(clock::instant, limit, duration, asList(1, 2, 3, 4)), iteratesAccordingToRateLimit(limit, duration, asList(1, 2, 3, 4), clock)); } @Test(timeout = 100, expected = IterationInterruptedException.class) public void rateLimitingDelayIsInterruptible() throws InterruptedException { - Thread testThread = Thread.currentThread(); - CountDownLatch latch = new CountDownLatch(1); + Thread testThread = Thread.currentThread(); + CountDownLatch latch = new CountDownLatch(1); new Thread(() -> { - Try.trying(latch::await).biMapL(AssertionError::new) - .orThrow(); + trying(sideEffect(latch::await)).orThrow(); testThread.interrupt(); }) {{ start(); diff --git a/src/test/java/com/jnape/palatable/lambda/functions/recursion/TrampolineTest.java b/src/test/java/com/jnape/palatable/lambda/functions/recursion/TrampolineTest.java index 035358e6a..5104aa824 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/recursion/TrampolineTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/recursion/TrampolineTest.java @@ -1,11 +1,11 @@ package com.jnape.palatable.lambda.functions.recursion; import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn1; import org.junit.Test; import java.math.BigInteger; import java.util.Map; -import java.util.function.Function; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; @@ -17,7 +17,8 @@ public class TrampolineTest { - private static final Function, RecursiveResult, BigInteger>> FACTORIAL = + private static final + Fn1, RecursiveResult, BigInteger>> FACTORIAL = into((x, acc) -> x.compareTo(ONE) > 0 ? recurse(tuple(x.subtract(ONE), x.multiply(acc))) : terminate(acc)); @Test diff --git a/src/test/java/com/jnape/palatable/lambda/functions/specialized/BiPredicateTest.java b/src/test/java/com/jnape/palatable/lambda/functions/specialized/BiPredicateTest.java index 4a19bbba8..9f472f37c 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/specialized/BiPredicateTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/specialized/BiPredicateTest.java @@ -13,44 +13,44 @@ public class BiPredicateTest { public void jufBiPredicateTest() { BiPredicate equals = String::equals; - assertTrue(equals.test("abc", "abc")); - assertFalse(equals.test("abc", "")); - assertFalse(equals.test("", "abc")); + assertTrue(equals.apply("abc", "abc")); + assertFalse(equals.apply("abc", "")); + assertFalse(equals.apply("", "abc")); } @Test public void jufBiPredicateAnd() { - BiPredicate bothOdd = (x, y) -> x % 2 == 1 && y % 2 == 1; + BiPredicate bothOdd = (x, y) -> x % 2 == 1 && y % 2 == 1; BiPredicate greaterThan = (x, y) -> x.compareTo(y) > 0; BiPredicate conjunction = bothOdd.and(greaterThan); - assertTrue(conjunction.test(3, 1)); - assertFalse(conjunction.test(3, 2)); - assertFalse(conjunction.test(3, 5)); - assertFalse(conjunction.test(4, 1)); + assertTrue(conjunction.apply(3, 1)); + assertFalse(conjunction.apply(3, 2)); + assertFalse(conjunction.apply(3, 5)); + assertFalse(conjunction.apply(4, 1)); } @Test public void jufBiPredicateOr() { - BiPredicate bothOdd = (x, y) -> x % 2 == 1 && y % 2 == 1; + BiPredicate bothOdd = (x, y) -> x % 2 == 1 && y % 2 == 1; BiPredicate greaterThan = (x, y) -> x.compareTo(y) > 0; BiPredicate disjunction = bothOdd.or(greaterThan); - assertTrue(disjunction.test(3, 2)); - assertTrue(disjunction.test(1, 3)); - assertFalse(disjunction.test(1, 2)); + assertTrue(disjunction.apply(3, 2)); + assertTrue(disjunction.apply(1, 3)); + assertFalse(disjunction.apply(1, 2)); } @Test public void jufBiPredicateNegate() { BiPredicate equals = String::equals; - assertTrue(equals.test("a", "a")); - assertFalse(equals.test("b", "a")); - assertFalse(equals.negate().test("a", "a")); - assertTrue(equals.negate().test("b", "a")); + assertTrue(equals.apply("a", "a")); + assertFalse(equals.apply("b", "a")); + assertFalse(equals.negate().apply("a", "a")); + assertTrue(equals.negate().apply("b", "a")); } @Test @@ -58,4 +58,18 @@ public void flip() { BiPredicate equals = String::equals; assertThat(equals.flip(), instanceOf(BiPredicate.class)); } + + @Test + public void fromPredicate() { + java.util.function.BiPredicate jufBiPredicate = Object::equals; + BiPredicate biPredicate = BiPredicate.fromBiPredicate(jufBiPredicate); + assertTrue(biPredicate.apply("a", "a")); + } + + @Test + public void toPredicate() { + BiPredicate biPredicate = Object::equals; + java.util.function.BiPredicate jufBiPredicate = biPredicate.toBiPredicate(); + assertTrue(jufBiPredicate.test("a", "a")); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/specialized/KleisliTest.java b/src/test/java/com/jnape/palatable/lambda/functions/specialized/KleisliTest.java index bd40b2dca..8be6844fe 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/specialized/KleisliTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/specialized/KleisliTest.java @@ -9,8 +9,8 @@ public class KleisliTest { - private static final Kleisli> G = kleisli(i -> new Identity<>(i.toString())); - private static final Kleisli> F = kleisli(s -> new Identity<>(parseInt(s))); + private static final Kleisli, Identity> G = kleisli(i -> new Identity<>(i.toString())); + private static final Kleisli, Identity> F = kleisli(s -> new Identity<>(parseInt(s))); @Test public void leftToRightComposition() { diff --git a/src/test/java/com/jnape/palatable/lambda/functions/specialized/PredicateTest.java b/src/test/java/com/jnape/palatable/lambda/functions/specialized/PredicateTest.java index b7c8be809..67ec6fe6a 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/specialized/PredicateTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/specialized/PredicateTest.java @@ -8,47 +8,61 @@ public class PredicateTest { @Test - public void jufPredicateTest() { + public void happyPath() { Predicate notEmpty = s -> !(s == null || s.length() == 0); - assertTrue(notEmpty.test("foo")); - assertFalse(notEmpty.test("")); - assertFalse(notEmpty.test(null)); + assertTrue(notEmpty.apply("foo")); + assertFalse(notEmpty.apply("")); + assertFalse(notEmpty.apply(null)); } @Test - public void jufPredicateAnd() { - Predicate notEmpty = s -> !(s == null || s.length() == 0); + public void and() { + Predicate notEmpty = s -> !(s == null || s.length() == 0); Predicate lengthGt1 = s -> s.length() > 1; Predicate conjunction = notEmpty.and(lengthGt1); - assertTrue(conjunction.test("fo")); - assertFalse(conjunction.test("f")); - assertFalse(conjunction.test("")); - assertFalse(conjunction.test(null)); + assertTrue(conjunction.apply("fo")); + assertFalse(conjunction.apply("f")); + assertFalse(conjunction.apply("")); + assertFalse(conjunction.apply(null)); } @Test - public void jufPredicateOr() { - Predicate notEmpty = s -> !(s == null || s.length() == 0); + public void or() { + Predicate notEmpty = s -> !(s == null || s.length() == 0); Predicate lengthGt1 = s -> s != null && s.length() > 1; Predicate disjunction = lengthGt1.or(notEmpty); - assertTrue(disjunction.test("fo")); - assertTrue(disjunction.test("f")); - assertFalse(disjunction.test("")); - assertFalse(disjunction.test(null)); + assertTrue(disjunction.apply("fo")); + assertTrue(disjunction.apply("f")); + assertFalse(disjunction.apply("")); + assertFalse(disjunction.apply(null)); } @Test - public void jufPredicateNegate() { + public void negate() { Predicate isTrue = x -> x; - assertTrue(isTrue.test(true)); - assertFalse(isTrue.test(false)); - assertFalse(isTrue.negate().test(true)); - assertTrue(isTrue.negate().test(false)); + assertTrue(isTrue.apply(true)); + assertFalse(isTrue.apply(false)); + assertFalse(isTrue.negate().apply(true)); + assertTrue(isTrue.negate().apply(false)); + } + + @Test + public void fromPredicate() { + java.util.function.Predicate jufPredicate = String::isEmpty; + Predicate predicate = Predicate.fromPredicate(jufPredicate); + assertFalse(predicate.apply("123")); + } + + @Test + public void toPredicate() { + Predicate predicate = String::isEmpty; + java.util.function.Predicate jufPredicate = predicate.toPredicate(); + assertFalse(jufPredicate.test("123")); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/specialized/PureTest.java b/src/test/java/com/jnape/palatable/lambda/functions/specialized/PureTest.java new file mode 100644 index 000000000..cda6be607 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/specialized/PureTest.java @@ -0,0 +1,16 @@ +package com.jnape.palatable.lambda.functions.specialized; + +import com.jnape.palatable.lambda.adt.Maybe; +import org.junit.Test; + +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static org.junit.Assert.assertEquals; + +public class PureTest { + + @Test + @SuppressWarnings("RedundantTypeArguments") + public void inference() { + assertEquals(just(1), Pure.>pure(Maybe::just).>apply(1)); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/specialized/SideEffectTest.java b/src/test/java/com/jnape/palatable/lambda/functions/specialized/SideEffectTest.java new file mode 100644 index 000000000..64eecfd3b --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/specialized/SideEffectTest.java @@ -0,0 +1,28 @@ +package com.jnape.palatable.lambda.functions.specialized; + +import org.junit.Test; + +import java.util.concurrent.atomic.AtomicInteger; + +import static org.junit.Assert.assertEquals; + +public class SideEffectTest { + + @Test + public void fromRunnable() throws Throwable { + AtomicInteger counter = new AtomicInteger(0); + Runnable runnable = counter::incrementAndGet; + SideEffect sideEffect = SideEffect.fromRunnable(runnable); + sideEffect.Ω(); + assertEquals(1, counter.get()); + } + + @Test + public void toRunnable() { + AtomicInteger counter = new AtomicInteger(0); + SideEffect sideEffect = counter::incrementAndGet; + Runnable runnable = sideEffect.toRunnable(); + runnable.run(); + assertEquals(1, counter.get()); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffectTest.java b/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffectTest.java deleted file mode 100644 index 8472dc067..000000000 --- a/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffectTest.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.jnape.palatable.lambda.functions.specialized.checked; - -import org.junit.Test; - -import java.util.ArrayList; -import java.util.List; - -import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; -import static java.util.Arrays.asList; -import static org.junit.Assert.assertEquals; - -public class CheckedEffectTest { - - @Test - public void assignment() { - List results = new ArrayList<>(); - - CheckedEffect effect = results::add; - CheckedEffect diMapL = effect.diMapL(Object::toString); - CheckedEffect contraMap = effect.contraMap(Object::toString); - CheckedEffect compose = effect.compose(Object::toString); - CheckedEffect stringEffect = effect.discardR(constantly("1")); - CheckedEffect andThen = effect.andThen(effect); - - effect.accept("1"); - diMapL.accept("2"); - contraMap.accept("3"); - compose.accept("4"); - stringEffect.accept("5"); - andThen.accept("6"); - - assertEquals(asList("1", "2", "3", "4", "5", "6", "6"), results); - } -} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1Test.java b/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1Test.java deleted file mode 100644 index a8818d684..000000000 --- a/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1Test.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.jnape.palatable.lambda.functions.specialized.checked; - -import com.jnape.palatable.lambda.adt.hlist.Tuple2; -import org.junit.Test; - -import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; -import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; -import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; -import static org.junit.Assert.assertEquals; - -public class CheckedFn1Test { - - @Test - public void assignment() { - CheckedFn1 parseInt = Integer::parseInt; - CheckedFn1 fmap = parseInt.fmap(Object::toString); - CheckedFn1 flatMap = parseInt.flatMap(i -> constantly(i + "")); - CheckedFn1 discardL = parseInt.discardL(constantly("0")); - CheckedFn1 discardR = parseInt.discardR(constantly("0")); - CheckedFn1 zipApp = parseInt.zip(constantly(id())); - CheckedFn1 zipF = parseInt.zip(constantly()); - CheckedFn1 diMapL = parseInt.diMapL(id()); - CheckedFn1 diMapR = parseInt.diMapR(id()); - CheckedFn1 diMap = parseInt.diMap(id(), id()); - CheckedFn1, Tuple2> strengthen = parseInt.strengthen(); - CheckedFn1> carry = parseInt.carry(); - CheckedFn1 contraMap = parseInt.contraMap(id()); - CheckedFn1 compose = parseInt.compose(id()); - CheckedFn1 andThen = parseInt.andThen(id()); - - assertEquals((Integer) 1, parseInt.apply("1")); - assertEquals("1", fmap.apply("1")); - assertEquals("1", flatMap.apply("1")); - assertEquals("0", discardL.apply("1")); - assertEquals((Integer) 1, discardR.apply("1")); - assertEquals((Integer) 1, zipApp.apply("1")); - assertEquals("1", zipF.apply("1")); - assertEquals((Integer) 1, diMapL.apply("1")); - assertEquals((Integer) 1, diMapR.apply("1")); - assertEquals((Integer) 1, diMap.apply("1")); - assertEquals(tuple("foo", 1), strengthen.apply(tuple("foo", "1"))); - assertEquals(tuple("1", 1), carry.apply("1")); - assertEquals((Integer) 1, contraMap.apply("1")); - assertEquals((Integer) 1, compose.apply("1")); - assertEquals((Integer) 1, andThen.apply("1")); - } -} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedSupplierTest.java b/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedSupplierTest.java deleted file mode 100644 index 804b77ca0..000000000 --- a/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedSupplierTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.jnape.palatable.lambda.functions.specialized.checked; - -import com.jnape.palatable.lambda.adt.Unit; -import com.jnape.palatable.lambda.adt.hlist.Tuple2; -import com.jnape.palatable.lambda.functions.builtin.fn1.Constantly; -import org.junit.Test; - -import static com.jnape.palatable.lambda.adt.Unit.UNIT; -import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; -import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; -import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; -import static com.jnape.palatable.lambda.functions.specialized.checked.CheckedSupplier.checked; -import static org.junit.Assert.assertEquals; - -public class CheckedSupplierTest { - - @Test - public void assignment() { - CheckedSupplier intSupplier = checked(() -> 1); - CheckedSupplier fmap = intSupplier.fmap(Object::toString); - @SuppressWarnings("RedundantTypeArguments") - CheckedSupplier flatMap = intSupplier.flatMap(Constantly::constantly); - CheckedSupplier discardL = intSupplier.discardL(constantly(1)); - CheckedSupplier discardR = intSupplier.discardR(constantly(2)); - CheckedSupplier zipA = intSupplier.zip(constantly(id())); - CheckedSupplier zipF = intSupplier.zip(constantly()); - CheckedSupplier diMapR = intSupplier.diMapR(id()); - CheckedSupplier> carry = intSupplier.carry(); - CheckedSupplier andThen = intSupplier.andThen(id()); - - assertEquals((Integer) 1, intSupplier.get()); - assertEquals("1", fmap.get()); - assertEquals((Integer) 1, flatMap.get()); - assertEquals((Integer) 1, discardL.get()); - assertEquals((Integer) 1, discardR.get()); - assertEquals((Integer) 1, zipA.get()); - assertEquals(UNIT, zipF.get()); - assertEquals((Integer) 1, diMapR.get()); - assertEquals(tuple(UNIT, 1), carry.get()); - assertEquals((Integer) 1, andThen.get()); - } -} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functor/BifunctorTest.java b/src/test/java/com/jnape/palatable/lambda/functor/BifunctorTest.java index ce89ba26e..88e027a8a 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/BifunctorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/BifunctorTest.java @@ -1,10 +1,10 @@ package com.jnape.palatable.lambda.functor; +import com.jnape.palatable.lambda.functions.Fn1; import org.junit.Test; import testsupport.applicatives.InvocationRecordingBifunctor; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static org.hamcrest.CoreMatchers.is; @@ -14,16 +14,18 @@ public class BifunctorTest { @Test public void biMapLUsesIdentityForRightBiMapFunction() { - AtomicReference rightInvocation = new AtomicReference<>(); - Bifunctor bifunctor = new InvocationRecordingBifunctor<>(new AtomicReference<>(), rightInvocation); + AtomicReference> rightInvocation = new AtomicReference<>(); + Bifunctor> bifunctor = + new InvocationRecordingBifunctor<>(new AtomicReference<>(), rightInvocation); bifunctor.biMapL(String::toUpperCase); assertThat(rightInvocation.get(), is(id())); } @Test public void biMapRUsesIdentityForLeftBiMapFunction() { - AtomicReference leftInvocation = new AtomicReference<>(); - Bifunctor bifunctor = new InvocationRecordingBifunctor<>(leftInvocation, new AtomicReference<>()); + AtomicReference> leftInvocation = new AtomicReference<>(); + Bifunctor> bifunctor = + new InvocationRecordingBifunctor<>(leftInvocation, new AtomicReference<>()); bifunctor.biMapR(String::valueOf); assertThat(leftInvocation.get(), is(id())); } diff --git a/src/test/java/com/jnape/palatable/lambda/functor/ProfunctorTest.java b/src/test/java/com/jnape/palatable/lambda/functor/ProfunctorTest.java index 0f7358250..6d1a34912 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/ProfunctorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/ProfunctorTest.java @@ -1,10 +1,10 @@ package com.jnape.palatable.lambda.functor; +import com.jnape.palatable.lambda.functions.Fn1; import org.junit.Test; import testsupport.applicatives.InvocationRecordingProfunctor; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static org.hamcrest.CoreMatchers.is; @@ -14,16 +14,18 @@ public class ProfunctorTest { @Test public void diMapLUsesIdentityForRightDiMapFunction() { - AtomicReference rightInvocation = new AtomicReference<>(); - Profunctor profunctor = new InvocationRecordingProfunctor<>(new AtomicReference<>(), rightInvocation); + AtomicReference> rightInvocation = new AtomicReference<>(); + Profunctor> profunctor = + new InvocationRecordingProfunctor<>(new AtomicReference<>(), rightInvocation); profunctor.diMapL(Object::toString); assertThat(rightInvocation.get(), is(id())); } @Test public void diMapRUsesIdentityForLeftDiMapFunction() { - AtomicReference leftInvocation = new AtomicReference<>(); - Profunctor profunctor = new InvocationRecordingProfunctor<>(leftInvocation, new AtomicReference<>()); + AtomicReference> leftInvocation = new AtomicReference<>(); + Profunctor> profunctor = + new InvocationRecordingProfunctor<>(leftInvocation, new AtomicReference<>()); profunctor.diMapR(String::valueOf); assertThat(leftInvocation.get(), is(id())); } diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/ComposeTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/ComposeTest.java index 3cc6198fc..dc994a3b0 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/builtin/ComposeTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/ComposeTest.java @@ -9,15 +9,17 @@ import testsupport.traits.ApplicativeLaws; import testsupport.traits.FunctorLaws; +import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.Either.right; import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static org.junit.Assert.assertEquals; @RunWith(Traits.class) public class ComposeTest { @TestTraits({FunctorLaws.class, ApplicativeLaws.class}) - public Compose testSubject() { + public Compose, Identity, Integer> testSubject() { return new Compose<>(new Identity<>(new Identity<>(1))); } @@ -26,4 +28,14 @@ public void inference() { Either> a = new Compose<>(right(just(1))).fmap(x -> x + 1).getCompose(); assertEquals(right(just(2)), a); } + + @Test + public void lazyZip() { + assertEquals(new Compose<>(right(just(2))), + new Compose<>(right(just(1))).lazyZip(lazy(new Compose<>(right(just(x -> x + 1))))).value()); + assertEquals(new Compose<>(left("foo")), + new Compose<>(left("foo")).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/ConstTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/ConstTest.java index 45588a462..da90a8592 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/builtin/ConstTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/ConstTest.java @@ -13,7 +13,7 @@ public class ConstTest { @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) - public Const testSubject() { + public Const testSubject() { return new Const<>(1); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/IdentityTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/IdentityTest.java index 7a46afd1d..242a5aaa0 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/builtin/IdentityTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/IdentityTest.java @@ -12,7 +12,7 @@ public class IdentityTest { @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, TraversableLaws.class}) - public Identity testSubject() { + public Identity testSubject() { return new Identity<>(""); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/LazyTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/LazyTest.java new file mode 100644 index 000000000..b169b7870 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/LazyTest.java @@ -0,0 +1,66 @@ +package com.jnape.palatable.lambda.functor.builtin; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; +import org.junit.runner.RunWith; +import testsupport.EquatableM; +import testsupport.traits.ApplicativeLaws; +import testsupport.traits.FunctorLaws; +import testsupport.traits.MonadLaws; + +import java.util.concurrent.atomic.AtomicBoolean; + +import static com.jnape.palatable.lambda.functions.builtin.fn3.Times.times; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static testsupport.Constants.STACK_EXPLODING_NUMBER; + +@RunWith(Traits.class) +public class LazyTest { + + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + public EquatableM, Integer> testSubject() { + return new EquatableM<>(lazy(0), Lazy::value); + } + + @Test + public void valueExtraction() { + assertEquals("foo", lazy("foo").value()); + assertEquals("foo", lazy(() -> "foo").value()); + } + + @Test + public void lazyEvaluation() { + AtomicBoolean invoked = new AtomicBoolean(false); + Lazy lazy = lazy(0).flatMap(x -> { + invoked.set(true); + return lazy(x + 1); + }); + assertFalse(invoked.get()); + assertEquals((Integer) 1, lazy.value()); + assertTrue(invoked.get()); + } + + @Test + public void linearStackSafety() { + assertEquals(STACK_EXPLODING_NUMBER, + times(STACK_EXPLODING_NUMBER, f -> f.fmap(x -> x + 1), lazy(0)).value()); + } + + @Test + public void recursiveStackSafety() { + assertEquals(STACK_EXPLODING_NUMBER, + new Fn1, Lazy>() { + @Override + public Lazy checkedApply(Lazy lazyX) { + return lazyX.flatMap(x -> x < STACK_EXPLODING_NUMBER + ? apply(lazy(x + 1)) + : lazy(x)); + } + }.apply(lazy(0)).value()); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/MarketTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/MarketTest.java new file mode 100644 index 000000000..d4009918e --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/MarketTest.java @@ -0,0 +1,29 @@ +package com.jnape.palatable.lambda.functor.builtin; + +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.framework.Subjects; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.runner.RunWith; +import testsupport.EquatableM; +import testsupport.traits.ApplicativeLaws; +import testsupport.traits.FunctorLaws; +import testsupport.traits.MonadLaws; + +import static com.jnape.palatable.lambda.adt.Either.trying; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Both.both; +import static com.jnape.palatable.traitor.framework.Subjects.subjects; +import static java.lang.Integer.parseInt; + +@RunWith(Traits.class) +public class MarketTest { + + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + public Subjects, String>> testSubject() { + Market market = new Market<>(id(), str -> trying(() -> parseInt(str), + constantly(str))); + return subjects(new EquatableM<>(market, m -> both(m.bt(), m.sta(), "123")), + new EquatableM<>(market, m -> both(m.bt(), m.sta(), "foo"))); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java new file mode 100644 index 000000000..f2071a27e --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java @@ -0,0 +1,83 @@ +package com.jnape.palatable.lambda.functor.builtin; + +import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.adt.hlist.HList; +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; +import org.junit.runner.RunWith; +import testsupport.EquatableM; +import testsupport.traits.ApplicativeLaws; +import testsupport.traits.FunctorLaws; +import testsupport.traits.MonadLaws; + +import static com.jnape.palatable.lambda.adt.Unit.UNIT; +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.adt.product.Product2.product; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; +import static org.junit.Assert.assertEquals; + +@RunWith(Traits.class) +public class StateTest { + + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + public EquatableM, Unit> testSubject() { + return new EquatableM<>(State.get(), state -> state.run(UNIT).into(HList::tuple)); + } + + @Test + public void eval() { + State state = State.put(0); + assertEquals(state.run(1)._1(), state.eval(1)); + } + + @Test + public void exec() { + State state = State.put(0); + assertEquals(state.run(1)._2(), state.exec(1)); + } + + @Test + public void get() { + assertEquals(tuple(1, 1), State.get().run(1)); + } + + @Test + public void put() { + assertEquals(tuple(UNIT, 1), State.put(1).run(1)); + } + + @Test + public void gets() { + assertEquals(tuple(0, "0"), State.gets(Integer::parseInt).run("0")); + } + + @Test + public void modify() { + assertEquals(tuple(UNIT, 1), State.modify(x -> x + 1).run(0)); + } + + @Test + public void state() { + assertEquals(tuple(1, UNIT), State.state(1).run(UNIT)); + assertEquals(tuple(1, -1), State.state(x -> product(x + 1, x - 1)).run(0)); + } + + @Test + public void stateAccumulation() { + State counter = State.get().flatMap(i -> State.put(i + 1).discardL(State.state(i))); + assertEquals(tuple(0, 1), counter.run(0)); + } + + @Test + public void withState() { + State modified = State.get().withState(x -> x + 1); + assertEquals(tuple(1, 1), modified.run(0)); + } + + @Test + public void mapState() { + State modified = State.get().mapState(into((a, s) -> product(a + 1, s + 2))); + assertEquals(tuple(1, 2), modified.run(0)); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/CombinatorialIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/CombinatorialIteratorTest.java similarity index 97% rename from src/test/java/com/jnape/palatable/lambda/iteration/CombinatorialIteratorTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/CombinatorialIteratorTest.java index 7678bd2c4..639136dd7 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/CombinatorialIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/CombinatorialIteratorTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import org.junit.Before; import org.junit.Test; diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/ConcatenatingIterableTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ConcatenatingIterableTest.java similarity index 94% rename from src/test/java/com/jnape/palatable/lambda/iteration/ConcatenatingIterableTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/ConcatenatingIterableTest.java index c82efdc70..92ffd28b9 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/ConcatenatingIterableTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ConcatenatingIterableTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/ConsingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ConsingIteratorTest.java similarity index 80% rename from src/test/java/com/jnape/palatable/lambda/iteration/ConsingIteratorTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/ConsingIteratorTest.java index 68f99d943..85f6c6ba0 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/ConsingIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ConsingIteratorTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import org.junit.Before; import org.junit.Test; @@ -9,6 +9,7 @@ import static com.jnape.palatable.lambda.functions.builtin.fn2.Iterate.iterate; import static com.jnape.palatable.lambda.functions.builtin.fn2.Take.take; import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldRight.foldRight; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -51,9 +52,10 @@ public void doesNotHaveNextIfNoElementsLeft() { @Test public void stackSafety() { Integer stackBlowingNumber = 10_000; - Iterable ints = foldRight((x, acc) -> () -> new ConsingIterator<>(x, acc), - (Iterable) Collections.emptyList(), - take(stackBlowingNumber, iterate(x -> x + 1, 1))); + Iterable ints = foldRight((x, lazyAcc) -> lazyAcc.fmap(acc -> () -> new ConsingIterator<>(x, acc)), + lazy((Iterable) Collections.emptyList()), + take(stackBlowingNumber, iterate(x -> x + 1, 1))) + .value(); assertEquals(stackBlowingNumber, take(1, drop(stackBlowingNumber - 1, ints)).iterator().next()); diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/CyclicIterableTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/CyclicIterableTest.java similarity index 88% rename from src/test/java/com/jnape/palatable/lambda/iteration/CyclicIterableTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/CyclicIterableTest.java index 66938afa1..a4ce12dce 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/CyclicIterableTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/CyclicIterableTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/CyclicIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/CyclicIteratorTest.java similarity index 92% rename from src/test/java/com/jnape/palatable/lambda/iteration/CyclicIteratorTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/CyclicIteratorTest.java index ba7e84485..5af519d32 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/CyclicIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/CyclicIteratorTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import org.junit.Test; diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/DistinctIterableTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/DistinctIterableTest.java similarity index 88% rename from src/test/java/com/jnape/palatable/lambda/iteration/DistinctIterableTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/DistinctIterableTest.java index 69a2bd252..ae6d53ce5 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/DistinctIterableTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/DistinctIterableTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/DroppingIterableTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/DroppingIterableTest.java similarity index 88% rename from src/test/java/com/jnape/palatable/lambda/iteration/DroppingIterableTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/DroppingIterableTest.java index 52ab7899f..cccdd2878 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/DroppingIterableTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/DroppingIterableTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/DroppingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/DroppingIteratorTest.java similarity index 91% rename from src/test/java/com/jnape/palatable/lambda/iteration/DroppingIteratorTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/DroppingIteratorTest.java index 0e28a2dd2..b13dc33d1 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/DroppingIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/DroppingIteratorTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import org.junit.Before; import org.junit.Test; @@ -17,7 +17,7 @@ public class DroppingIteratorTest { @Mock private Iterator iterator; - private DroppingIterator droppingIterator; + private DroppingIterator droppingIterator; @Before public void setUp() { diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/FilteringIterableTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/FilteringIterableTest.java similarity index 91% rename from src/test/java/com/jnape/palatable/lambda/iteration/FilteringIterableTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/FilteringIterableTest.java index 7d1c645d6..b2f40b516 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/FilteringIterableTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/FilteringIterableTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/FilteringIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/FilteringIteratorTest.java similarity index 95% rename from src/test/java/com/jnape/palatable/lambda/iteration/FilteringIteratorTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/FilteringIteratorTest.java index 5f2c3cb7e..68f3ab567 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/FilteringIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/FilteringIteratorTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import org.junit.Test; diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/FlatteningIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/FlatteningIteratorTest.java similarity index 96% rename from src/test/java/com/jnape/palatable/lambda/iteration/FlatteningIteratorTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/FlatteningIteratorTest.java index 7288e8fbc..ce286ecd2 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/FlatteningIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/FlatteningIteratorTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import org.junit.Test; diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/GroupingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/GroupingIteratorTest.java similarity index 96% rename from src/test/java/com/jnape/palatable/lambda/iteration/GroupingIteratorTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/GroupingIteratorTest.java index 0caab11a5..0288574d2 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/GroupingIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/GroupingIteratorTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import org.junit.Before; import org.junit.Test; diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/ImmutableIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ImmutableIteratorTest.java similarity index 77% rename from src/test/java/com/jnape/palatable/lambda/iteration/ImmutableIteratorTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/ImmutableIteratorTest.java index d1ffc6ebd..15369f60a 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/ImmutableIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ImmutableIteratorTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import org.junit.Before; import org.junit.Test; @@ -7,11 +7,11 @@ public class ImmutableIteratorTest { - private ImmutableIterator immutableIterator; + private ImmutableIterator immutableIterator; @Before public void setUp() { - immutableIterator = new ImmutableIterator() { + immutableIterator = new ImmutableIterator() { @Override public boolean hasNext() { throw outOfScope(); diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/InfiniteIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/InfiniteIteratorTest.java similarity index 79% rename from src/test/java/com/jnape/palatable/lambda/iteration/InfiniteIteratorTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/InfiniteIteratorTest.java index 9d9f8abd5..a2df8b32c 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/InfiniteIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/InfiniteIteratorTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import org.junit.Before; import org.junit.Test; @@ -9,11 +9,11 @@ public class InfiniteIteratorTest { - private InfiniteIterator infiniteIterator; + private InfiniteIterator infiniteIterator; @Before public void setUp() { - infiniteIterator = new InfiniteIterator() { + infiniteIterator = new InfiniteIterator() { @Override public Object next() { throw outOfScope(); diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/InitIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/InitIteratorTest.java similarity index 94% rename from src/test/java/com/jnape/palatable/lambda/iteration/InitIteratorTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/InitIteratorTest.java index 04c512cb3..99f12dee2 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/InitIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/InitIteratorTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import org.junit.Test; diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/MappingIterableTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/MappingIterableTest.java similarity index 91% rename from src/test/java/com/jnape/palatable/lambda/iteration/MappingIterableTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/MappingIterableTest.java index fdddf37e0..b86b95650 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/MappingIterableTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/MappingIterableTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/MappingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/MappingIteratorTest.java similarity index 91% rename from src/test/java/com/jnape/palatable/lambda/iteration/MappingIteratorTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/MappingIteratorTest.java index c4522f8c1..396982cdc 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/MappingIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/MappingIteratorTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import com.jnape.palatable.lambda.functions.Fn1; import org.junit.Test; diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterableTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterableTest.java similarity index 91% rename from src/test/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterableTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterableTest.java index 2202c2b98..55d6a3ef1 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterableTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterableTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIteratorTest.java similarity index 97% rename from src/test/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIteratorTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIteratorTest.java index 68f933a9a..bb3afa82f 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIteratorTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import com.jnape.palatable.lambda.functions.Fn1; import org.junit.Before; diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterableTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedTakingIterableTest.java similarity index 91% rename from src/test/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterableTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedTakingIterableTest.java index bb8738cc5..e819c90f2 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterableTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedTakingIterableTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedTakingIteratorTest.java similarity index 98% rename from src/test/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIteratorTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedTakingIteratorTest.java index 833ad43c8..70ba8953f 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedTakingIteratorTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import com.jnape.palatable.lambda.functions.specialized.Predicate; import org.junit.Test; diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/PrependingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/PrependingIteratorTest.java similarity index 96% rename from src/test/java/com/jnape/palatable/lambda/iteration/PrependingIteratorTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/PrependingIteratorTest.java index 84bdebc1a..4e922aa43 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/PrependingIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/PrependingIteratorTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import org.junit.Rule; import org.junit.Test; diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/RepetitiousIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/RepetitiousIteratorTest.java similarity index 93% rename from src/test/java/com/jnape/palatable/lambda/iteration/RepetitiousIteratorTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/RepetitiousIteratorTest.java index bcf9d2628..f99823f25 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/RepetitiousIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/RepetitiousIteratorTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import org.junit.Before; import org.junit.Test; diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/ReversingIterableTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ReversingIterableTest.java similarity index 90% rename from src/test/java/com/jnape/palatable/lambda/iteration/ReversingIterableTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/ReversingIterableTest.java index e70b7cbd9..44ea4f446 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/ReversingIterableTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ReversingIterableTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/ReversingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ReversingIteratorTest.java similarity index 91% rename from src/test/java/com/jnape/palatable/lambda/iteration/ReversingIteratorTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/ReversingIteratorTest.java index 754345bfb..1fd9afce1 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/ReversingIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ReversingIteratorTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import org.junit.Before; import org.junit.Test; @@ -22,7 +22,7 @@ public class ReversingIteratorTest { @Mock private Iterator iterator; - private ReversingIterator reversingIterator; + private ReversingIterator reversingIterator; @Before public void setUp() { @@ -47,6 +47,7 @@ public void reversesIterator() { } @Test + @SuppressWarnings("ResultOfMethodCallIgnored") public void doesNotReverseUntilNextIsCalled() { reversingIterator.hasNext(); verify(iterator, never()).next(); @@ -63,6 +64,7 @@ public void doesNotHaveNextIfFinishedReversingIterator() { } @Test + @SuppressWarnings("ResultOfMethodCallIgnored") public void neverInteractsWithIteratorAgainAfterInitialReverse() { mockIteratorToHaveValues(iterator, 1, 2, 3); diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/RewindableIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/RewindableIteratorTest.java similarity index 94% rename from src/test/java/com/jnape/palatable/lambda/iteration/RewindableIteratorTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/RewindableIteratorTest.java index 3e1498b90..532397934 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/RewindableIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/RewindableIteratorTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import org.junit.Before; import org.junit.Test; @@ -18,7 +18,7 @@ public class RewindableIteratorTest { @Mock private Iterator iterator; - private RewindableIterator rewindableIterator; + private RewindableIterator rewindableIterator; @Before public void setUp() { diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/ScanningIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ScanningIteratorTest.java similarity index 88% rename from src/test/java/com/jnape/palatable/lambda/iteration/ScanningIteratorTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/ScanningIteratorTest.java index cde0c2f1b..43d24fad0 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/ScanningIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ScanningIteratorTest.java @@ -1,9 +1,9 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; +import com.jnape.palatable.lambda.functions.Fn2; import org.junit.Test; import java.util.NoSuchElementException; -import java.util.function.BiFunction; import static java.util.Arrays.asList; import static java.util.Collections.emptyIterator; @@ -12,7 +12,7 @@ public class ScanningIteratorTest { - public static final BiFunction ADD = (x, y) -> x + y; + public static final Fn2 ADD = Integer::sum; @Test public void hasNextAtLeastForB() { diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/SnocIterableTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/SnocIterableTest.java similarity index 89% rename from src/test/java/com/jnape/palatable/lambda/iteration/SnocIterableTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/SnocIterableTest.java index 258e872a3..6451e8b4f 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/SnocIterableTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/SnocIterableTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/SnocIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/SnocIteratorTest.java similarity index 95% rename from src/test/java/com/jnape/palatable/lambda/iteration/SnocIteratorTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/SnocIteratorTest.java index 6fca49817..96080f32b 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/SnocIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/SnocIteratorTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import org.junit.Before; import org.junit.Test; diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/TakingIterableTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/TakingIterableTest.java similarity index 90% rename from src/test/java/com/jnape/palatable/lambda/iteration/TakingIterableTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/TakingIterableTest.java index b1bd84454..e72b6f060 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/TakingIterableTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/TakingIterableTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/TakingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/TakingIteratorTest.java similarity index 91% rename from src/test/java/com/jnape/palatable/lambda/iteration/TakingIteratorTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/TakingIteratorTest.java index 9f17bcf4d..d22dd8138 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/TakingIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/TakingIteratorTest.java @@ -1,11 +1,11 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import org.junit.Test; +import java.util.Collections; import java.util.List; import static java.util.Arrays.asList; -import static java.util.Collections.emptyList; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; @@ -40,7 +40,7 @@ public void doesNotHaveNextIfTakenAllOfIterable() { @Test public void doesNotHaveNextForEmptyIterable() { - TakingIterator takingIterator = new TakingIterator<>(3, emptyList().iterator()); + TakingIterator takingIterator = new TakingIterator<>(3, Collections.emptyIterator()); assertThat(takingIterator.hasNext(), is(false)); } } diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/UnfoldingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/UnfoldingIteratorTest.java similarity index 96% rename from src/test/java/com/jnape/palatable/lambda/iteration/UnfoldingIteratorTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/UnfoldingIteratorTest.java index 68fa1ec9c..4b1199565 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/UnfoldingIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/UnfoldingIteratorTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.hlist.Tuple2; diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/UnioningIterableTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/UnioningIterableTest.java similarity index 94% rename from src/test/java/com/jnape/palatable/lambda/iteration/UnioningIterableTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/UnioningIterableTest.java index dddec5ad9..b28bc2b61 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/UnioningIterableTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/UnioningIterableTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/ZippingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ZippingIteratorTest.java similarity index 85% rename from src/test/java/com/jnape/palatable/lambda/iteration/ZippingIteratorTest.java rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/ZippingIteratorTest.java index f88705a91..96e655db0 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/ZippingIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ZippingIteratorTest.java @@ -1,5 +1,6 @@ -package com.jnape.palatable.lambda.iteration; +package com.jnape.palatable.lambda.internal.iteration; +import com.jnape.palatable.lambda.functions.Fn2; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -7,7 +8,6 @@ import org.mockito.runners.MockitoJUnitRunner; import java.util.Iterator; -import java.util.function.BiFunction; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; @@ -17,9 +17,9 @@ @RunWith(MockitoJUnitRunner.class) public class ZippingIteratorTest { - @Mock private BiFunction zipper; - @Mock private Iterator as; - @Mock private Iterator bs; + @Mock private Fn2 zipper; + @Mock private Iterator as; + @Mock private Iterator bs; private ZippingIterator zippingIterator; diff --git a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java new file mode 100644 index 000000000..2c86683e3 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java @@ -0,0 +1,246 @@ +package com.jnape.palatable.lambda.io; + +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; +import org.junit.runner.RunWith; +import testsupport.EquatableM; +import testsupport.traits.ApplicativeLaws; +import testsupport.traits.FunctorLaws; +import testsupport.traits.MonadLaws; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; + +import static com.jnape.palatable.lambda.adt.Either.left; +import static com.jnape.palatable.lambda.adt.Either.right; +import static com.jnape.palatable.lambda.adt.Unit.UNIT; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Tupler2.tupler; +import static com.jnape.palatable.lambda.functions.builtin.fn3.Times.times; +import static com.jnape.palatable.lambda.io.IO.externallyManaged; +import static com.jnape.palatable.lambda.io.IO.io; +import static java.util.concurrent.CompletableFuture.completedFuture; +import static java.util.concurrent.Executors.newFixedThreadPool; +import static java.util.concurrent.ForkJoinPool.commonPool; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static testsupport.Constants.STACK_EXPLODING_NUMBER; + +@RunWith(Traits.class) +public class IOTest { + + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + public EquatableM, Integer> testSubject() { + return new EquatableM<>(io(1), IO::unsafePerformIO); + } + + @Test + public void staticFactoryMethods() { + assertEquals((Integer) 1, io(1).unsafePerformIO()); + assertEquals((Integer) 1, io(() -> 1).unsafePerformIO()); + assertEquals(UNIT, io(() -> {}).unsafePerformIO()); + } + + @Test(timeout = 100) + public void unsafePerformAsyncIOWithoutExecutor() { + assertEquals((Integer) 1, io(() -> 1).unsafePerformAsyncIO().join()); + } + + @Test(timeout = 100) + public void unsafePerformAsyncIOWithExecutor() { + assertEquals((Integer) 1, io(() -> 1).unsafePerformAsyncIO(newFixedThreadPool(1)).join()); + } + + @Test + public void zipAndDerivativesComposesInParallel() { + String a = "foo"; + Fn1> f = tupler(1); + + ExecutorService executor = newFixedThreadPool(2); + CountDownLatch advanceFirst = new CountDownLatch(1); + CountDownLatch advanceSecond = new CountDownLatch(1); + + IO ioA = io(() -> { + advanceFirst.countDown(); + advanceSecond.await(); + return a; + }); + IO>> ioF = io(() -> { + advanceFirst.await(); + advanceSecond.countDown(); + return f; + }); + + IO> zip = ioA.zip(ioF); + assertEquals(f.apply(a), zip.unsafePerformAsyncIO().join()); + assertEquals(f.apply(a), zip.unsafePerformAsyncIO(executor).join()); + assertEquals(f.apply(a), zip.unsafePerformAsyncIO(executor).join()); + + IO>> discardL = ioA.discardL(ioF); + assertEquals(f, discardL.unsafePerformAsyncIO().join()); + assertEquals(f, discardL.unsafePerformAsyncIO(executor).join()); + + IO discardR = ioA.discardR(ioF); + assertEquals(a, discardR.unsafePerformAsyncIO().join()); + assertEquals(a, discardR.unsafePerformAsyncIO(executor).join()); + } + + @Test + public void delegatesToExternallyManagedFuture() { + CompletableFuture future = completedFuture(1); + IO io = externallyManaged(() -> future); + assertEquals((Integer) 1, io.unsafePerformIO()); + assertEquals((Integer) 1, io.unsafePerformAsyncIO().join()); + assertEquals((Integer) 1, io.unsafePerformAsyncIO(commonPool()).join()); + } + + @Test + public void exceptionallyRecoversThrowableToResult() { + IO io = io(() -> { throw new UnsupportedOperationException("foo"); }); + assertEquals("foo", io.exceptionally(Throwable::getMessage).unsafePerformIO()); + + IO externallyManaged = externallyManaged(() -> new CompletableFuture() {{ + completeExceptionally(new UnsupportedOperationException("foo")); + }}).exceptionally(e -> e.getCause().getMessage()); + assertEquals("foo", externallyManaged.unsafePerformIO()); + } + + @Test + public void exceptionallyRescuesFutures() { + ExecutorService executor = newFixedThreadPool(2); + + IO io = io(() -> { throw new UnsupportedOperationException("foo"); }); + assertEquals("foo", io.exceptionally(e -> e.getCause().getMessage()).unsafePerformAsyncIO().join()); + assertEquals("foo", io.exceptionally(e -> e.getCause().getMessage()).unsafePerformAsyncIO(executor).join()); + + IO externallyManaged = externallyManaged(() -> new CompletableFuture() {{ + completeExceptionally(new UnsupportedOperationException("foo")); + }}).exceptionally(e -> e.getCause().getMessage()); + assertEquals("foo", externallyManaged.unsafePerformIO()); + } + + @Test + public void linearSyncStackSafety() { + assertEquals(STACK_EXPLODING_NUMBER, + times(STACK_EXPLODING_NUMBER, f -> f.fmap(x -> x + 1), io(0)).unsafePerformIO()); + assertEquals(STACK_EXPLODING_NUMBER, + times(STACK_EXPLODING_NUMBER, f -> f.zip(f.pure(x -> x + 1)), io(0)).unsafePerformIO()); + assertEquals((Integer) 0, + times(STACK_EXPLODING_NUMBER, f -> f.pure(0).discardR(f), io(0)).unsafePerformIO()); + assertEquals((Integer) 1, + times(STACK_EXPLODING_NUMBER, f -> f.pure(1).discardR(f), io(0)).unsafePerformIO()); + assertEquals((Integer) 0, + times(STACK_EXPLODING_NUMBER, f -> f.pure(1).discardL(f), io(0)).unsafePerformIO()); + assertEquals(STACK_EXPLODING_NUMBER, + times(STACK_EXPLODING_NUMBER, f -> f.flatMap(x -> f.pure(x + 1)), io(0)).unsafePerformIO()); + } + + @Test + public void recursiveSyncFlatMapStackSafety() { + assertEquals(STACK_EXPLODING_NUMBER, + new Fn1, IO>() { + @Override + public IO checkedApply(IO a) { + return a.flatMap(x -> x < STACK_EXPLODING_NUMBER ? apply(io(x + 1)) : io(x)); + } + }.apply(io(0)).unsafePerformIO()); + + } + + @Test + public void linearAsyncStackSafety() { + assertEquals(STACK_EXPLODING_NUMBER, + times(STACK_EXPLODING_NUMBER, f -> f.fmap(x -> x + 1), io(0)).unsafePerformAsyncIO().join()); + assertEquals(STACK_EXPLODING_NUMBER, + times(STACK_EXPLODING_NUMBER, f -> f.zip(f.pure(x -> x + 1)), io(0)).unsafePerformAsyncIO() + .join()); + assertEquals((Integer) 0, + times(STACK_EXPLODING_NUMBER, f -> f.pure(0).discardR(f), io(0)).unsafePerformAsyncIO().join()); + assertEquals((Integer) 1, + times(STACK_EXPLODING_NUMBER, f -> f.pure(1).discardR(f), io(0)).unsafePerformAsyncIO().join()); + assertEquals((Integer) 0, + times(STACK_EXPLODING_NUMBER, f -> f.pure(1).discardL(f), io(0)).unsafePerformAsyncIO().join()); + assertEquals(STACK_EXPLODING_NUMBER, + times(STACK_EXPLODING_NUMBER, f -> f.flatMap(x -> f.pure(x + 1)), io(0)).unsafePerformAsyncIO() + .join()); + } + + @Test + public void recursiveAsyncFlatMapStackSafety() { + assertEquals(STACK_EXPLODING_NUMBER, + new Fn1, IO>() { + @Override + public IO checkedApply(IO a) { + return a.flatMap(x -> x < STACK_EXPLODING_NUMBER ? apply(io(x + 1)) : io(x)); + } + }.apply(io(0)).unsafePerformAsyncIO().join()); + } + + @Test + public void safe() { + assertEquals(right(1), io(() -> 1).safe().unsafePerformIO()); + IllegalStateException thrown = new IllegalStateException("kaboom"); + assertEquals(left(thrown), io(() -> {throw thrown;}).safe().unsafePerformIO()); + } + + @Test + public void ensuring() { + AtomicInteger counter = new AtomicInteger(0); + IO incCounter = io(counter::incrementAndGet); + assertEquals("foo", io(() -> "foo").ensuring(incCounter).unsafePerformIO()); + assertEquals(1, counter.get()); + + IllegalStateException thrown = new IllegalStateException("kaboom"); + try { + io(() -> {throw thrown;}).ensuring(incCounter).unsafePerformIO(); + fail("Expected exception to have been thrown, but wasn't."); + } catch (IllegalStateException actual) { + assertEquals(thrown, actual); + assertEquals(2, counter.get()); + } + } + + @Test + public void ensuringRunsStrictlyAfterIO() { + Executor twoThreads = Executors.newFixedThreadPool(2); + AtomicInteger counter = new AtomicInteger(0); + io(() -> { + Thread.sleep(100); + counter.incrementAndGet(); + }).ensuring(io(() -> { + if (counter.get() == 0) + fail("Expected to run after initial IO, but ran first"); + })).unsafePerformAsyncIO(twoThreads).join(); + } + + @Test + public void ensuringAttachesThrownExceptionToThrownBodyException() { + IllegalStateException thrownByBody = new IllegalStateException("kaboom"); + IllegalStateException thrownByEnsuring = new IllegalStateException("KABOOM"); + + try { + io(() -> {throw thrownByBody;}).ensuring(io(() -> {throw thrownByEnsuring;})).unsafePerformIO(); + fail("Expected exception to have been thrown, but wasn't."); + } catch (IllegalStateException actual) { + assertEquals(thrownByBody, actual); + assertArrayEquals(new Throwable[]{thrownByEnsuring}, actual.getSuppressed()); + } + } + + @Test + public void throwing() { + IllegalStateException expected = new IllegalStateException("thrown"); + try { + IO.throwing(expected).unsafePerformIO(); + } catch (IllegalStateException actual) { + assertEquals(expected, actual); + } + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java new file mode 100644 index 000000000..b5d717b69 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java @@ -0,0 +1,39 @@ +package com.jnape.palatable.lambda.monad.transformer.builtin; + +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.framework.Subjects; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; +import org.junit.runner.RunWith; +import testsupport.traits.ApplicativeLaws; +import testsupport.traits.FunctorLaws; +import testsupport.traits.MonadLaws; + +import static com.jnape.palatable.lambda.adt.Either.left; +import static com.jnape.palatable.lambda.adt.Either.right; +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; +import static com.jnape.palatable.lambda.monad.transformer.builtin.EitherT.eitherT; +import static com.jnape.palatable.traitor.framework.Subjects.subjects; +import static org.junit.Assert.assertEquals; + +@RunWith(Traits.class) +public class EitherTTest { + + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + public Subjects, String, Integer>> testSubject() { + return subjects(eitherT(new Identity<>(left("foo"))), eitherT(new Identity<>(right(1)))); + } + + @Test + public void lazyZip() { + assertEquals(eitherT(just(right(2))), + eitherT(just(right(1))).lazyZip(lazy(eitherT(just(right(x -> x + 1))))).value()); + assertEquals(eitherT(nothing()), + eitherT(nothing()).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityTTest.java new file mode 100644 index 000000000..fb9a6629d --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityTTest.java @@ -0,0 +1,37 @@ +package com.jnape.palatable.lambda.monad.transformer.builtin; + +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; +import org.junit.runner.RunWith; +import testsupport.traits.ApplicativeLaws; +import testsupport.traits.FunctorLaws; +import testsupport.traits.MonadLaws; + +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; +import static com.jnape.palatable.lambda.monad.transformer.builtin.IdentityT.identityT; +import static org.junit.Assert.assertEquals; + +@RunWith(Traits.class) +public class IdentityTTest { + + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + public IdentityT, Integer> testSubject() { + return identityT(just(new Identity<>(1))); + } + + @Test + public void lazyZip() { + assertEquals(identityT(just(new Identity<>(2))), + identityT(just(new Identity<>(1))) + .lazyZip(lazy(identityT(just(new Identity<>(x -> x + 1))))).value()); + assertEquals(identityT(nothing()), + identityT(nothing()).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyTTest.java new file mode 100644 index 000000000..87dffb7e6 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyTTest.java @@ -0,0 +1,36 @@ +package com.jnape.palatable.lambda.monad.transformer.builtin; + +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; +import org.junit.runner.RunWith; +import testsupport.traits.ApplicativeLaws; +import testsupport.traits.FunctorLaws; +import testsupport.traits.MonadLaws; + +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; +import static com.jnape.palatable.lambda.monad.transformer.builtin.LazyT.lazyT; +import static org.junit.Assert.assertEquals; + +@RunWith(Traits.class) +public class LazyTTest { + + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + public LazyT, Integer> testSubject() { + return lazyT(just(lazy(1))); + } + + @Test + public void lazyZip() { + assertEquals(lazyT(just(lazy(2))), + lazyT(just(lazy(1))) + .lazyZip(lazy(lazyT(just(lazy(x -> x + 1))))).value()); + assertEquals(lazyT(nothing()), + lazyT(nothing()).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java new file mode 100644 index 000000000..9a5368cdc --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java @@ -0,0 +1,41 @@ +package com.jnape.palatable.lambda.monad.transformer.builtin; + +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.framework.Subjects; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; +import org.junit.runner.RunWith; +import testsupport.traits.ApplicativeLaws; +import testsupport.traits.FunctorLaws; +import testsupport.traits.MonadLaws; + +import static com.jnape.palatable.lambda.adt.Either.left; +import static com.jnape.palatable.lambda.adt.Either.right; +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; +import static com.jnape.palatable.lambda.monad.transformer.builtin.MaybeT.maybeT; +import static com.jnape.palatable.traitor.framework.Subjects.subjects; +import static org.junit.Assert.assertEquals; + +@RunWith(Traits.class) +public class MaybeTTest { + + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + public Subjects, Integer>> testSubject() { + return subjects(maybeT(right(just(1))), + maybeT(right(nothing())), + maybeT(left("foo"))); + } + + @Test + public void lazyZip() { + assertEquals(maybeT(right(just(2))), + maybeT(right(just(1))).lazyZip(lazy(maybeT(right(just(x -> x + 1))))).value()); + assertEquals(maybeT(left("foo")), + maybeT(left("foo")).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/AddAllTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/AddAllTest.java index 8a997382b..c1aaf214f 100644 --- a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/AddAllTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/AddAllTest.java @@ -13,6 +13,7 @@ public class AddAllTest { @Test + @SuppressWarnings("serial") public void monoid() { Monoid> addAll = addAll(HashSet::new); diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/RunAllTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/RunAllTest.java index 782ee334f..c0e9f6d17 100644 --- a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/RunAllTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/RunAllTest.java @@ -3,7 +3,7 @@ import com.jnape.palatable.lambda.monoid.Monoid; import org.junit.Test; -import static com.jnape.palatable.lambda.functions.IO.io; +import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.lambda.monoid.builtin.RunAll.runAll; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/TrivialTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/TrivialTest.java new file mode 100644 index 000000000..da28c59f6 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/TrivialTest.java @@ -0,0 +1,16 @@ +package com.jnape.palatable.lambda.monoid.builtin; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.adt.Unit.UNIT; +import static com.jnape.palatable.lambda.monoid.builtin.Trivial.trivial; +import static org.junit.Assert.assertEquals; + +public class TrivialTest { + + @Test + public void triviality() { + assertEquals(UNIT, trivial().identity()); + assertEquals(UNIT, trivial().apply(UNIT, UNIT)); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/lens/IsoTest.java b/src/test/java/com/jnape/palatable/lambda/optics/IsoTest.java similarity index 80% rename from src/test/java/com/jnape/palatable/lambda/lens/IsoTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/IsoTest.java index 016de15ee..91c181029 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/IsoTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/IsoTest.java @@ -1,11 +1,11 @@ -package com.jnape.palatable.lambda.lens; +package com.jnape.palatable.lambda.optics; import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; import org.junit.runner.RunWith; -import testsupport.EqualityAwareIso; +import testsupport.EquatableM; import testsupport.traits.ApplicativeLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; @@ -13,9 +13,9 @@ import java.util.List; import static com.jnape.palatable.lambda.adt.Maybe.just; -import static com.jnape.palatable.lambda.lens.Iso.iso; -import static com.jnape.palatable.lambda.lens.functions.Set.set; -import static com.jnape.palatable.lambda.lens.functions.View.view; +import static com.jnape.palatable.lambda.optics.Iso.iso; +import static com.jnape.palatable.lambda.optics.functions.Set.set; +import static com.jnape.palatable.lambda.optics.functions.View.view; import static java.util.Arrays.asList; import static java.util.stream.Collectors.toList; import static org.junit.Assert.assertEquals; @@ -27,8 +27,8 @@ public class IsoTest { iso(Integer::parseInt, dbl -> dbl.toString().chars().mapToObj(x -> (char) x).collect(toList())); @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) - public Iso, Integer, Double> testSubject() { - return new EqualityAwareIso<>("123", 1.23d, ISO); + public EquatableM, List> testSubject() { + return new EquatableM<>(ISO, iso -> view(iso, "123")); } @Test diff --git a/src/test/java/com/jnape/palatable/lambda/lens/LensTest.java b/src/test/java/com/jnape/palatable/lambda/optics/LensTest.java similarity index 66% rename from src/test/java/com/jnape/palatable/lambda/lens/LensTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/LensTest.java index 12d94b30c..f5b1cbf2a 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/LensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/LensTest.java @@ -1,14 +1,15 @@ -package com.jnape.palatable.lambda.lens; +package com.jnape.palatable.lambda.optics; import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.builtin.Const; import com.jnape.palatable.lambda.functor.builtin.Identity; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; import org.junit.runner.RunWith; -import testsupport.EqualityAwareLens; +import testsupport.EquatableM; import testsupport.traits.ApplicativeLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; @@ -19,11 +20,11 @@ import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; -import static com.jnape.palatable.lambda.lens.Lens.both; -import static com.jnape.palatable.lambda.lens.Lens.lens; -import static com.jnape.palatable.lambda.lens.Lens.simpleLens; -import static com.jnape.palatable.lambda.lens.functions.Set.set; -import static com.jnape.palatable.lambda.lens.functions.View.view; +import static com.jnape.palatable.lambda.optics.Lens.both; +import static com.jnape.palatable.lambda.optics.Lens.lens; +import static com.jnape.palatable.lambda.optics.Lens.simpleLens; +import static com.jnape.palatable.lambda.optics.functions.Set.set; +import static com.jnape.palatable.lambda.optics.functions.View.view; import static java.lang.Integer.parseInt; import static java.util.Arrays.asList; import static java.util.Collections.emptyMap; @@ -35,23 +36,30 @@ @RunWith(Traits.class) public class LensTest { - private static final Lens>, Map>, List, Set> EARLIER_LENS = lens(m -> m.get("foo"), (m, s) -> singletonMap("foo", s)); - private static final Lens, Set, String, Integer> LENS = lens(xs -> xs.get(0), (xs, i) -> singleton(i)); + private static final Lens>, Map>, List, Set> + EARLIER_LENS = lens(m -> m.get("foo"), (m, s) -> singletonMap("foo", s)); + private static final Lens, Set, String, Integer> + LENS = lens(xs -> xs.get(0), (xs, i) -> singleton(i)); @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) - public Lens, List, Integer, String> testSubject() { - return new EqualityAwareLens<>(emptyMap(), lens(m -> m.get("foo"), (m, s) -> singletonList(m.get(s)))); + public EquatableM, ?, Integer, String>, List> testSubject() { + return new EquatableM<>(lens(m -> m.get("foo"), (m, s) -> singletonList(m.get(s))), + lens -> view(lens, emptyMap())); } @Test public void setsUnderIdentity() { - Set ints = LENS.>, Identity>apply(s -> new Identity<>(s.length()), asList("foo", "bar", "baz")).runIdentity(); + Set ints = LENS., Identity, Identity, Identity>, + Fn1>, Fn1, Identity>>>apply( + s -> new Identity<>(s.length())).apply(asList("foo", "bar", "baz")).runIdentity(); assertEquals(singleton(3), ints); } @Test public void viewsUnderConst() { - Integer i = LENS., Const>, Const>apply(s -> new Const<>(s.length()), asList("foo", "bar", "baz")).runConst(); + Integer i = LENS., Const, Const, Const>, + Fn1>, Fn1, Const>>>apply( + s -> new Const<>(s.length())).apply(asList("foo", "bar", "baz")).runConst(); assertEquals((Integer) 3, i); } @@ -65,10 +73,12 @@ public void mapsIndividuallyOverParameters() { .mapB((Maybe maybeI) -> maybeI.orElse(-1)); assertEquals(just(true), - theGambit.>, Identity>>apply( - maybeC -> new Identity<>(maybeC.fmap(c -> parseInt(Character.toString(c)))), - just("321")).runIdentity() - ); + theGambit., Identity, Identity>, Identity>, + Fn1, Identity>>, + Fn1, Identity>>>apply( + maybeC -> new Identity<>(maybeC.fmap(c -> parseInt(Character.toString(c))))) + .apply(just("321")) + .runIdentity()); } @Test diff --git a/src/test/java/com/jnape/palatable/lambda/optics/OpticTest.java b/src/test/java/com/jnape/palatable/lambda/optics/OpticTest.java new file mode 100644 index 000000000..00a550185 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/optics/OpticTest.java @@ -0,0 +1,44 @@ +package com.jnape.palatable.lambda.optics; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.Functor; +import com.jnape.palatable.lambda.functor.Profunctor; +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.functor.builtin.Tagged; +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.optics.Optic.optic; +import static org.junit.Assert.assertEquals; + +public class OpticTest { + + @Test + public void monomorphize() { + Optic, Identity, String, String, String, String> optic = optic(pafb -> pafb); + Fn1>, Tagged>> monomorphize = optic.monomorphize(); + assertEquals(new Identity<>("foo"), monomorphize.apply(new Tagged<>(new Identity<>("foo"))).unTagged()); + } + + @Test + public void reframe() { + Optic, Functor, String, String, String, String> optic = optic(pafb -> pafb); + Optic, Identity, String, String, String, String> reframed = Optic.reframe(optic); + assertEquals(new Identity<>("foo"), + reframed., Identity, Identity, Identity, + Fn1>, + Fn1>>apply(constantly(new Identity<>("foo"))).apply("bar")); + } + + @Test + public void adapt() { + Optic, Functor, String, String, String, String> optic = optic(pafb -> pafb); + Optic.Simple, Functor, String, String> simple = Optic.Simple.adapt(optic); + + assertEquals("foo", + simple., Identity, Identity, Identity, + Fn1>, + Fn1>>apply(constantly(new Identity<>("foo"))) + .apply("bar").runIdentity()); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java b/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java new file mode 100644 index 000000000..b2080bb0b --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java @@ -0,0 +1,63 @@ +package com.jnape.palatable.lambda.optics; + +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; +import org.junit.runner.RunWith; +import testsupport.EquatableM; +import testsupport.traits.ApplicativeLaws; +import testsupport.traits.FunctorLaws; +import testsupport.traits.MonadLaws; + +import static com.jnape.palatable.lambda.adt.Either.left; +import static com.jnape.palatable.lambda.adt.Either.right; +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.optics.Prism.prism; +import static com.jnape.palatable.lambda.optics.Prism.simplePrism; +import static com.jnape.palatable.lambda.optics.functions.Matching.matching; +import static com.jnape.palatable.lambda.optics.functions.Pre.pre; +import static com.jnape.palatable.lambda.optics.functions.Re.re; +import static com.jnape.palatable.lambda.optics.functions.View.view; +import static org.junit.Assert.assertEquals; + +@RunWith(Traits.class) +public class PrismTest { + + private static final Fn1 PARSE_INT = Fn1.fn1(Integer::parseInt); + + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + public EquatableM, String> testSubject() { + return new EquatableM<>(Prism.fromPartial(Integer::parseInt, Object::toString), + prism -> matching(prism, "foo")); + } + + @Test + public void prismLaws() { + Prism prism = prism(PARSE_INT.choose(), Object::toString); + + assertEquals(just(1), view(pre(prism), view(re(prism), 1))); + assertEquals(just(123), view(pre(prism), "123").filter(a -> view(re(prism), a).equals("123"))); + assertEquals(left("foo"), matching(prism, "foo").match(t -> matching(prism, t), Either::right)); + } + + @Test + @SuppressWarnings("unused") + public void simplePrismInference() { + Prism.Simple simplePrism = simplePrism(PARSE_INT.choose().fmap(CoProduct2::projectB), + Object::toString); + } + + @Test + public void unPrismExtractsMappings() { + Prism prism = prism(PARSE_INT.choose(), Object::toString); + Fn1 is = prism.unPrism()._1(); + Fn1> sis = prism.unPrism()._2(); + + assertEquals("123", is.apply(123)); + assertEquals(right(123), sis.apply("123")); + assertEquals(left("foo"), sis.apply("foo")); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/lens/functions/OverTest.java b/src/test/java/com/jnape/palatable/lambda/optics/functions/OverTest.java similarity index 68% rename from src/test/java/com/jnape/palatable/lambda/lens/functions/OverTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/functions/OverTest.java index e5a95cf4a..ef2adf7a6 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/functions/OverTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/functions/OverTest.java @@ -1,13 +1,13 @@ -package com.jnape.palatable.lambda.lens.functions; +package com.jnape.palatable.lambda.optics.functions; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Lens; import org.junit.Test; import java.util.List; import java.util.Set; -import static com.jnape.palatable.lambda.lens.Lens.lens; -import static com.jnape.palatable.lambda.lens.functions.Over.over; +import static com.jnape.palatable.lambda.optics.Lens.lens; +import static com.jnape.palatable.lambda.optics.functions.Over.over; import static java.util.Arrays.asList; import static java.util.Collections.singleton; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/com/jnape/palatable/lambda/optics/functions/PreTest.java b/src/test/java/com/jnape/palatable/lambda/optics/functions/PreTest.java new file mode 100644 index 000000000..d697108ee --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/optics/functions/PreTest.java @@ -0,0 +1,30 @@ +package com.jnape.palatable.lambda.optics.functions; + +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.optics.Iso; +import com.jnape.palatable.lambda.optics.Prism; +import org.junit.Test; + +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.optics.Iso.iso; +import static com.jnape.palatable.lambda.optics.Prism.prism; +import static com.jnape.palatable.lambda.optics.functions.Pre.pre; +import static com.jnape.palatable.lambda.optics.functions.View.view; +import static java.lang.Integer.parseInt; +import static org.junit.Assert.assertEquals; + +public class PreTest { + + @Test + public void focusOnAtMostOneValue() { + Iso iso = iso(Integer::parseInt, Object::toString); + Prism prism = prism(s -> Either.trying(() -> parseInt(s), + constantly(s)), + Object::toString); + assertEquals(just(1), view(pre(prism), "1")); + assertEquals(nothing(), view(pre(prism), "foo")); + assertEquals(just(1), view(pre(iso), "1")); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/optics/functions/ReTest.java b/src/test/java/com/jnape/palatable/lambda/optics/functions/ReTest.java new file mode 100644 index 000000000..a6d4fb900 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/optics/functions/ReTest.java @@ -0,0 +1,27 @@ +package com.jnape.palatable.lambda.optics.functions; + +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.optics.Iso; +import com.jnape.palatable.lambda.optics.Prism; +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.optics.Iso.iso; +import static com.jnape.palatable.lambda.optics.Prism.prism; +import static com.jnape.palatable.lambda.optics.functions.Re.re; +import static com.jnape.palatable.lambda.optics.functions.View.view; +import static java.lang.Integer.parseInt; +import static org.junit.Assert.assertEquals; + +public class ReTest { + + @Test + public void flipAroundIsoAndPrism() { + Iso iso = iso(Integer::parseInt, Object::toString); + Prism prism = prism(s -> Either.trying(() -> parseInt(s), + constantly(s)), + Object::toString); + assertEquals("1", view(re(prism), 1)); + assertEquals("1", view(re(iso), 1)); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/lens/functions/SetTest.java b/src/test/java/com/jnape/palatable/lambda/optics/functions/SetTest.java similarity index 67% rename from src/test/java/com/jnape/palatable/lambda/lens/functions/SetTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/functions/SetTest.java index 47fa8a959..11a6bdcc5 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/functions/SetTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/functions/SetTest.java @@ -1,12 +1,12 @@ -package com.jnape.palatable.lambda.lens.functions; +package com.jnape.palatable.lambda.optics.functions; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Lens; import org.junit.Test; import java.util.List; -import static com.jnape.palatable.lambda.lens.Lens.lens; -import static com.jnape.palatable.lambda.lens.functions.Set.set; +import static com.jnape.palatable.lambda.optics.Lens.lens; +import static com.jnape.palatable.lambda.optics.functions.Set.set; import static java.util.Arrays.asList; import static java.util.Collections.singleton; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/com/jnape/palatable/lambda/lens/functions/UnderTest.java b/src/test/java/com/jnape/palatable/lambda/optics/functions/UnderTest.java similarity index 68% rename from src/test/java/com/jnape/palatable/lambda/lens/functions/UnderTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/functions/UnderTest.java index 58d44f19f..15827500b 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/functions/UnderTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/functions/UnderTest.java @@ -1,14 +1,14 @@ -package com.jnape.palatable.lambda.lens.functions; +package com.jnape.palatable.lambda.optics.functions; -import com.jnape.palatable.lambda.lens.Iso; +import com.jnape.palatable.lambda.optics.Iso; import org.junit.Test; import java.util.Collections; import java.util.List; import java.util.Set; -import static com.jnape.palatable.lambda.lens.Iso.iso; -import static com.jnape.palatable.lambda.lens.functions.Under.under; +import static com.jnape.palatable.lambda.optics.Iso.iso; +import static com.jnape.palatable.lambda.optics.functions.Under.under; import static java.util.Collections.singletonList; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/com/jnape/palatable/lambda/lens/functions/ViewTest.java b/src/test/java/com/jnape/palatable/lambda/optics/functions/ViewTest.java similarity index 67% rename from src/test/java/com/jnape/palatable/lambda/lens/functions/ViewTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/functions/ViewTest.java index 201ec990a..07f7a047a 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/functions/ViewTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/functions/ViewTest.java @@ -1,13 +1,13 @@ -package com.jnape.palatable.lambda.lens.functions; +package com.jnape.palatable.lambda.optics.functions; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Lens; import org.junit.Test; import java.util.List; import java.util.Set; -import static com.jnape.palatable.lambda.lens.Lens.lens; -import static com.jnape.palatable.lambda.lens.functions.View.view; +import static com.jnape.palatable.lambda.optics.Lens.lens; +import static com.jnape.palatable.lambda.optics.functions.View.view; import static java.util.Arrays.asList; import static java.util.Collections.singleton; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/com/jnape/palatable/lambda/lens/lenses/CollectionLensTest.java b/src/test/java/com/jnape/palatable/lambda/optics/lenses/CollectionLensTest.java similarity index 80% rename from src/test/java/com/jnape/palatable/lambda/lens/lenses/CollectionLensTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/lenses/CollectionLensTest.java index 07d88c2de..1c13ef7c9 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/lenses/CollectionLensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/lenses/CollectionLensTest.java @@ -1,6 +1,6 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Lens; import org.junit.Test; import java.util.ArrayList; @@ -8,10 +8,10 @@ import java.util.List; import java.util.stream.Stream; -import static com.jnape.palatable.lambda.lens.functions.Set.set; -import static com.jnape.palatable.lambda.lens.functions.View.view; -import static com.jnape.palatable.lambda.lens.lenses.CollectionLens.asCopy; -import static com.jnape.palatable.lambda.lens.lenses.CollectionLens.asSet; +import static com.jnape.palatable.lambda.optics.functions.Set.set; +import static com.jnape.palatable.lambda.optics.functions.View.view; +import static com.jnape.palatable.lambda.optics.lenses.CollectionLens.asCopy; +import static com.jnape.palatable.lambda.optics.lenses.CollectionLens.asSet; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.emptySet; diff --git a/src/test/java/com/jnape/palatable/lambda/lens/lenses/EitherLensTest.java b/src/test/java/com/jnape/palatable/lambda/optics/lenses/EitherLensTest.java similarity index 83% rename from src/test/java/com/jnape/palatable/lambda/lens/lenses/EitherLensTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/lenses/EitherLensTest.java index 08bf1d3e3..ef9aee18d 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/lenses/EitherLensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/lenses/EitherLensTest.java @@ -1,23 +1,23 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; import com.jnape.palatable.lambda.adt.Either; import com.jnape.palatable.lambda.adt.Maybe; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Lens; import org.junit.Test; import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.Either.right; import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; -import static com.jnape.palatable.lambda.lens.functions.Set.set; -import static com.jnape.palatable.lambda.lens.functions.View.view; +import static com.jnape.palatable.lambda.optics.functions.Set.set; +import static com.jnape.palatable.lambda.optics.functions.View.view; import static org.junit.Assert.assertEquals; public class EitherLensTest { @Test public void rightFocusesOnRightValues() { - Lens.Simple, Maybe> right = EitherLens.right(); + Lens.Simple, Maybe> right = EitherLens._right(); assertEquals(just(1), view(right, right(1))); assertEquals(nothing(), view(right, left("fail"))); @@ -29,7 +29,7 @@ public void rightFocusesOnRightValues() { @Test public void leftFocusesOnLeftValues() { - Lens.Simple, Maybe> left = EitherLens.left(); + Lens.Simple, Maybe> left = EitherLens._left(); assertEquals(just("fail"), view(left, left("fail"))); assertEquals(nothing(), view(left, right(1))); diff --git a/src/test/java/com/jnape/palatable/lambda/lens/lenses/HListLensTest.java b/src/test/java/com/jnape/palatable/lambda/optics/lenses/HListLensTest.java similarity index 90% rename from src/test/java/com/jnape/palatable/lambda/lens/lenses/HListLensTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/lenses/HListLensTest.java index 6296ff3ef..09c8de717 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/lenses/HListLensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/lenses/HListLensTest.java @@ -1,11 +1,11 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; import com.jnape.palatable.lambda.adt.hlist.Index; import org.junit.Test; import static com.jnape.palatable.lambda.adt.hlist.HList.singletonHList; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; -import static com.jnape.palatable.lambda.lens.lenses.HListLens.elementAt; +import static com.jnape.palatable.lambda.optics.lenses.HListLens.elementAt; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; import static testsupport.assertion.LensAssert.assertLensLawfulness; diff --git a/src/test/java/com/jnape/palatable/lambda/lens/lenses/HMapLensTest.java b/src/test/java/com/jnape/palatable/lambda/optics/lenses/HMapLensTest.java similarity index 96% rename from src/test/java/com/jnape/palatable/lambda/lens/lenses/HMapLensTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/lenses/HMapLensTest.java index 66073427e..94041fb6e 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/lenses/HMapLensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/lenses/HMapLensTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; import com.jnape.palatable.lambda.adt.hmap.TypeSafeKey; import org.junit.Test; diff --git a/src/test/java/com/jnape/palatable/lambda/lens/lenses/IterableLensTest.java b/src/test/java/com/jnape/palatable/lambda/optics/lenses/IterableLensTest.java similarity index 87% rename from src/test/java/com/jnape/palatable/lambda/lens/lenses/IterableLensTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/lenses/IterableLensTest.java index 561bc4d99..3353c9eed 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/lenses/IterableLensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/lenses/IterableLensTest.java @@ -1,17 +1,17 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; import com.jnape.palatable.lambda.adt.Maybe; -import com.jnape.palatable.lambda.lens.Iso; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Iso; +import com.jnape.palatable.lambda.optics.Lens; import org.junit.Test; import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; -import static com.jnape.palatable.lambda.lens.Iso.simpleIso; -import static com.jnape.palatable.lambda.lens.functions.Over.over; -import static com.jnape.palatable.lambda.lens.functions.Set.set; -import static com.jnape.palatable.lambda.lens.functions.View.view; +import static com.jnape.palatable.lambda.optics.Iso.simpleIso; +import static com.jnape.palatable.lambda.optics.functions.Over.over; +import static com.jnape.palatable.lambda.optics.functions.Set.set; +import static com.jnape.palatable.lambda.optics.functions.View.view; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; diff --git a/src/test/java/com/jnape/palatable/lambda/lens/lenses/ListLensTest.java b/src/test/java/com/jnape/palatable/lambda/optics/lenses/ListLensTest.java similarity index 79% rename from src/test/java/com/jnape/palatable/lambda/lens/lenses/ListLensTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/lenses/ListLensTest.java index 78949c068..9a283f71c 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/lenses/ListLensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/lenses/ListLensTest.java @@ -1,16 +1,16 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Lens; import org.junit.Test; import java.util.List; import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; -import static com.jnape.palatable.lambda.lens.functions.Set.set; -import static com.jnape.palatable.lambda.lens.functions.View.view; -import static com.jnape.palatable.lambda.lens.lenses.ListLens.asCopy; -import static com.jnape.palatable.lambda.lens.lenses.ListLens.elementAt; +import static com.jnape.palatable.lambda.optics.functions.Set.set; +import static com.jnape.palatable.lambda.optics.functions.View.view; +import static com.jnape.palatable.lambda.optics.lenses.ListLens.asCopy; +import static com.jnape.palatable.lambda.optics.lenses.ListLens.elementAt; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; diff --git a/src/test/java/com/jnape/palatable/lambda/lens/lenses/MapLensTest.java b/src/test/java/com/jnape/palatable/lambda/optics/lenses/MapLensTest.java similarity index 94% rename from src/test/java/com/jnape/palatable/lambda/lens/lenses/MapLensTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/lenses/MapLensTest.java index 7a83e934a..5a97e5b4a 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/lenses/MapLensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/lenses/MapLensTest.java @@ -1,6 +1,6 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Lens; import org.junit.Test; import java.util.Collection; @@ -11,11 +11,11 @@ import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; -import static com.jnape.palatable.lambda.lens.Iso.iso; -import static com.jnape.palatable.lambda.lens.functions.Set.set; -import static com.jnape.palatable.lambda.lens.functions.View.view; -import static com.jnape.palatable.lambda.lens.lenses.MapLens.keys; -import static com.jnape.palatable.lambda.lens.lenses.MapLens.mappingValues; +import static com.jnape.palatable.lambda.optics.Iso.iso; +import static com.jnape.palatable.lambda.optics.functions.Set.set; +import static com.jnape.palatable.lambda.optics.functions.View.view; +import static com.jnape.palatable.lambda.optics.lenses.MapLens.keys; +import static com.jnape.palatable.lambda.optics.lenses.MapLens.mappingValues; import static java.util.Arrays.asList; import static java.util.Collections.emptyMap; import static java.util.Collections.emptySet; @@ -29,6 +29,7 @@ import static testsupport.assertion.LensAssert.assertLensLawfulness; import static testsupport.matchers.IterableMatcher.iterates; +@SuppressWarnings("serial") public class MapLensTest { @Test diff --git a/src/test/java/com/jnape/palatable/lambda/lens/lenses/MaybeLensTest.java b/src/test/java/com/jnape/palatable/lambda/optics/lenses/MaybeLensTest.java similarity index 80% rename from src/test/java/com/jnape/palatable/lambda/lens/lenses/MaybeLensTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/lenses/MaybeLensTest.java index 445aa8a73..4542be84b 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/lenses/MaybeLensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/lenses/MaybeLensTest.java @@ -1,19 +1,19 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; import com.jnape.palatable.lambda.adt.Maybe; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Lens; import org.junit.Before; import org.junit.Test; import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; -import static com.jnape.palatable.lambda.lens.Lens.lens; -import static com.jnape.palatable.lambda.lens.functions.Set.set; -import static com.jnape.palatable.lambda.lens.functions.View.view; -import static com.jnape.palatable.lambda.lens.lenses.MaybeLens.liftA; -import static com.jnape.palatable.lambda.lens.lenses.MaybeLens.liftB; -import static com.jnape.palatable.lambda.lens.lenses.MaybeLens.liftS; -import static com.jnape.palatable.lambda.lens.lenses.MaybeLens.liftT; +import static com.jnape.palatable.lambda.optics.Lens.lens; +import static com.jnape.palatable.lambda.optics.functions.Set.set; +import static com.jnape.palatable.lambda.optics.functions.View.view; +import static com.jnape.palatable.lambda.optics.lenses.MaybeLens.liftA; +import static com.jnape.palatable.lambda.optics.lenses.MaybeLens.liftB; +import static com.jnape.palatable.lambda.optics.lenses.MaybeLens.liftS; +import static com.jnape.palatable.lambda.optics.lenses.MaybeLens.liftT; import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; import static testsupport.assertion.LensAssert.assertLensLawfulness; diff --git a/src/test/java/com/jnape/palatable/lambda/lens/lenses/SetLensTest.java b/src/test/java/com/jnape/palatable/lambda/optics/lenses/SetLensTest.java similarity index 92% rename from src/test/java/com/jnape/palatable/lambda/lens/lenses/SetLensTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/lenses/SetLensTest.java index 9421e50f6..6beff4b53 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/lenses/SetLensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/lenses/SetLensTest.java @@ -1,11 +1,11 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; import org.junit.Test; import java.util.HashSet; import java.util.TreeSet; -import static com.jnape.palatable.lambda.lens.functions.Set.set; +import static com.jnape.palatable.lambda.optics.functions.Set.set; import static java.util.Arrays.asList; import static java.util.Collections.emptySet; import static java.util.Collections.singleton; diff --git a/src/test/java/com/jnape/palatable/lambda/optics/prisms/EitherPrismTest.java b/src/test/java/com/jnape/palatable/lambda/optics/prisms/EitherPrismTest.java new file mode 100644 index 000000000..cb1e09357 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/optics/prisms/EitherPrismTest.java @@ -0,0 +1,26 @@ +package com.jnape.palatable.lambda.optics.prisms; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.adt.Either.left; +import static com.jnape.palatable.lambda.adt.Either.right; +import static java.util.Arrays.asList; +import static java.util.Collections.singleton; +import static testsupport.assertion.PrismAssert.assertPrismLawfulness; + +public class EitherPrismTest { + + @Test + public void _right() { + assertPrismLawfulness(EitherPrism._right(), + asList(left("foo"), right(1)), + singleton(1)); + } + + @Test + public void _left() { + assertPrismLawfulness(EitherPrism._left(), + asList(left("foo"), right(1)), + singleton("foo")); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/optics/prisms/MapPrismTest.java b/src/test/java/com/jnape/palatable/lambda/optics/prisms/MapPrismTest.java new file mode 100644 index 000000000..7ba1dd09f --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/optics/prisms/MapPrismTest.java @@ -0,0 +1,33 @@ +package com.jnape.palatable.lambda.optics.prisms; + +import org.junit.Test; + +import java.util.HashMap; +import java.util.LinkedHashMap; + +import static java.util.Arrays.asList; +import static java.util.Collections.singleton; +import static java.util.Collections.singletonMap; +import static testsupport.assertion.PrismAssert.assertPrismLawfulness; + +public class MapPrismTest { + + @Test + public void valueAtWithConstructor() { + assertPrismLawfulness(MapPrism.valueAt(LinkedHashMap::new, "foo"), + asList(new LinkedHashMap<>(), + new LinkedHashMap<>(singletonMap("foo", 1)), + new LinkedHashMap<>(singletonMap("bar", 2))), + singleton(1)); + } + + @Test + public void valueAtWithoutConstructor() { + assertPrismLawfulness(MapPrism.valueAt("foo"), + asList(new HashMap<>(), + new HashMap<>(singletonMap("foo", 1)), + new HashMap<>(singletonMap("bar", 2))), + singleton(1)); + } + +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/optics/prisms/MaybePrismTest.java b/src/test/java/com/jnape/palatable/lambda/optics/prisms/MaybePrismTest.java new file mode 100644 index 000000000..5d772a6c5 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/optics/prisms/MaybePrismTest.java @@ -0,0 +1,27 @@ +package com.jnape.palatable.lambda.optics.prisms; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.adt.Unit.UNIT; +import static java.util.Arrays.asList; +import static java.util.Collections.singleton; +import static testsupport.assertion.PrismAssert.assertPrismLawfulness; + +public class MaybePrismTest { + + @Test + public void _just() { + assertPrismLawfulness(MaybePrism._just(), + asList(just(1), nothing()), + singleton(1)); + } + + @Test + public void _nothing() { + assertPrismLawfulness(MaybePrism._nothing(), + asList(just(1), nothing()), + singleton(UNIT)); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/optics/prisms/UUIDPrismTest.java b/src/test/java/com/jnape/palatable/lambda/optics/prisms/UUIDPrismTest.java new file mode 100644 index 000000000..24bf6421a --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/optics/prisms/UUIDPrismTest.java @@ -0,0 +1,20 @@ +package com.jnape.palatable.lambda.optics.prisms; + +import org.junit.Test; + +import java.util.UUID; + +import static java.util.Arrays.asList; +import static java.util.Collections.singleton; +import static testsupport.assertion.PrismAssert.assertPrismLawfulness; + +public class UUIDPrismTest { + + @Test + public void uuid() { + UUID uuid = UUID.randomUUID(); + assertPrismLawfulness(UUIDPrism.uuid(), + asList("", "123", uuid.toString()), + singleton(uuid)); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/SemigroupTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/SemigroupTest.java index 94697cda3..3291b6b1b 100644 --- a/src/test/java/com/jnape/palatable/lambda/semigroup/SemigroupTest.java +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/SemigroupTest.java @@ -1,6 +1,5 @@ package com.jnape.palatable.lambda.semigroup; -import com.jnape.palatable.lambda.semigroup.Semigroup; import org.junit.Test; import static java.util.Arrays.asList; @@ -17,6 +16,6 @@ public void foldLeft() { @Test public void foldRight() { Semigroup sum = (x, y) -> x + y; - assertEquals((Integer) 6, sum.foldRight(0, asList(1, 2, 3))); + assertEquals((Integer) 6, sum.foldRight(0, asList(1, 2, 3)).value()); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/EndoTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/EndoTest.java new file mode 100644 index 000000000..4da982462 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/EndoTest.java @@ -0,0 +1,21 @@ +package com.jnape.palatable.lambda.semigroup.builtin; + +import com.jnape.palatable.lambda.monoid.builtin.Endo; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class EndoTest { + + @Test + public void identity() { + assertEquals((Integer) 1, Endo.endo().identity().apply(1)); + } + + @Test + public void semigroup() { + assertEquals((Integer) 2, Endo.endo().apply(x -> x + 1, x -> x + 1).apply(0)); + assertEquals((Integer) 2, Endo.endo().apply(x -> x + 1, x -> x + 1, 0)); + assertEquals((Integer) 2, Endo.endo(x -> x + 1, x -> x + 1, 0)); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/IntersectionTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/IntersectionTest.java similarity index 92% rename from src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/IntersectionTest.java rename to src/test/java/com/jnape/palatable/lambda/semigroup/builtin/IntersectionTest.java index 13c16ace3..0ecd33c71 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/IntersectionTest.java +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/IntersectionTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.functions.builtin.fn2; +package com.jnape.palatable.lambda.semigroup.builtin; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; @@ -10,7 +10,7 @@ import testsupport.traits.InfiniteIterableSupport; import testsupport.traits.Laziness; -import static com.jnape.palatable.lambda.functions.builtin.fn2.Intersection.intersection; +import static com.jnape.palatable.lambda.semigroup.builtin.Intersection.intersection; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/RunAllTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/RunAllTest.java index c8840da69..329fe8429 100644 --- a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/RunAllTest.java +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/RunAllTest.java @@ -3,7 +3,7 @@ import com.jnape.palatable.lambda.semigroup.Semigroup; import org.junit.Test; -import static com.jnape.palatable.lambda.functions.IO.io; +import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.lambda.semigroup.builtin.RunAll.runAll; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/com/jnape/palatable/lambda/traversable/LambdaIterableTest.java b/src/test/java/com/jnape/palatable/lambda/traversable/LambdaIterableTest.java index 9947e7f3a..163fa5f20 100644 --- a/src/test/java/com/jnape/palatable/lambda/traversable/LambdaIterableTest.java +++ b/src/test/java/com/jnape/palatable/lambda/traversable/LambdaIterableTest.java @@ -1,5 +1,7 @@ package com.jnape.palatable.lambda.traversable; +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.framework.Subjects; import com.jnape.palatable.traitor.runners.Traits; @@ -10,13 +12,22 @@ import testsupport.traits.MonadLaws; import testsupport.traits.TraversableLaws; -import java.util.function.Function; - +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Size.size; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Cons.cons; import static com.jnape.palatable.lambda.functions.builtin.fn2.Replicate.replicate; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; +import static com.jnape.palatable.lambda.traversable.LambdaIterable.empty; +import static com.jnape.palatable.lambda.traversable.LambdaIterable.wrap; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static java.util.Arrays.asList; import static java.util.Collections.singleton; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; +import static testsupport.Constants.STACK_EXPLODING_NUMBER; import static testsupport.matchers.IterableMatcher.iterates; @RunWith(Traits.class) @@ -24,13 +35,36 @@ public class LambdaIterableTest { @TestTraits({FunctorLaws.class, ApplicativeLaws.class, TraversableLaws.class, MonadLaws.class}) public Subjects> testSubject() { - return subjects(LambdaIterable.empty(), LambdaIterable.wrap(singleton(1)), LambdaIterable.wrap(replicate(100, 1))); + return subjects(LambdaIterable.empty(), wrap(singleton(1)), wrap(replicate(100, 1))); } @Test public void zipAppliesCartesianProductOfFunctionsAndValues() { - LambdaIterable> fns = LambdaIterable.wrap(asList(x -> x + 1, x -> x - 1)); - LambdaIterable xs = LambdaIterable.wrap(asList(1, 2, 3)); + LambdaIterable> fns = wrap(asList(x -> x + 1, x -> x - 1)); + LambdaIterable xs = wrap(asList(1, 2, 3)); assertThat(xs.zip(fns).unwrap(), iterates(2, 3, 4, 0, 1, 2)); } + + @Test + public void earlyTraverseTermination() { + assertEquals(nothing(), wrap(repeat(1)).traverse(x -> nothing(), Maybe::just)); + assertEquals(nothing(), LambdaIterable.>wrap(cons(just(1), repeat(nothing()))) + .traverse(id(), Maybe::just)); + } + + @Test + public void traverseStackSafety() { + Maybe> traversed = wrap(replicate(STACK_EXPLODING_NUMBER, just(1))) + .traverse(id(), Maybe::just); + assertEquals(just(STACK_EXPLODING_NUMBER.longValue()), + traversed.fmap(LambdaIterable::unwrap).fmap(size())); + } + + @Test + public void lazyZip() { + assertEquals(wrap(singleton(2)), wrap(singleton(1)).lazyZip(lazy(wrap(singleton(x -> x + 1)))).value()); + assertEquals(empty(), empty().lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/traversable/LambdaMapTest.java b/src/test/java/com/jnape/palatable/lambda/traversable/LambdaMapTest.java index 9cffe9efb..2be8673f7 100644 --- a/src/test/java/com/jnape/palatable/lambda/traversable/LambdaMapTest.java +++ b/src/test/java/com/jnape/palatable/lambda/traversable/LambdaMapTest.java @@ -15,6 +15,7 @@ @RunWith(Traits.class) public class LambdaMapTest { + @SuppressWarnings("serial") @TestTraits({FunctorLaws.class, TraversableLaws.class}) public Subjects> testSubject() { return subjects(LambdaMap.empty(), diff --git a/src/test/java/testsupport/Constants.java b/src/test/java/testsupport/Constants.java new file mode 100644 index 000000000..a439920d6 --- /dev/null +++ b/src/test/java/testsupport/Constants.java @@ -0,0 +1,8 @@ +package testsupport; + +public final class Constants { + public static final Integer STACK_EXPLODING_NUMBER = 50_000; + + private Constants() { + } +} diff --git a/src/test/java/testsupport/EqualityAwareFn0.java b/src/test/java/testsupport/EqualityAwareFn0.java deleted file mode 100644 index 17b3318d5..000000000 --- a/src/test/java/testsupport/EqualityAwareFn0.java +++ /dev/null @@ -1,72 +0,0 @@ -package testsupport; - -import com.jnape.palatable.lambda.adt.Unit; -import com.jnape.palatable.lambda.functions.Fn0; -import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.monad.Monad; - -import java.util.function.Function; - -import static com.jnape.palatable.lambda.adt.Unit.UNIT; -import static java.util.Objects.hash; - -public final class EqualityAwareFn0 implements Fn0 { - private final Fn0 fn; - - public EqualityAwareFn0(Fn0 fn) { - this.fn = fn; - } - - @Override - public A apply() { - return fn.apply(); - } - - @Override - public A apply(Unit unit) { - return apply(); - } - - @Override - public EqualityAwareFn0 flatMap(Function>> f) { - return new EqualityAwareFn0<>(fn.flatMap(f)); - } - - @Override - public EqualityAwareFn0 fmap(Function f) { - return new EqualityAwareFn0<>(fn.fmap(f)); - } - - @Override - public EqualityAwareFn0 zip(Applicative, Fn1> appFn) { - return new EqualityAwareFn0<>(fn.zip(appFn)); - } - - @Override - public EqualityAwareFn0 pure(B b) { - return new EqualityAwareFn0<>(fn.pure(b)); - } - - - @Override - public EqualityAwareFn0 discardL(Applicative> appB) { - return new EqualityAwareFn0<>(fn.discardL(appB)); - } - - @Override - public EqualityAwareFn0 discardR(Applicative> appB) { - return new EqualityAwareFn0<>(fn.discardR(appB)); - } - - @Override - @SuppressWarnings("unchecked") - public boolean equals(Object other) { - return other instanceof Fn0 && ((Fn0) other).apply(UNIT).equals(apply(UNIT)); - } - - @Override - public int hashCode() { - return hash(fn); - } -} diff --git a/src/test/java/testsupport/EqualityAwareFn1.java b/src/test/java/testsupport/EqualityAwareFn1.java deleted file mode 100644 index 464962d19..000000000 --- a/src/test/java/testsupport/EqualityAwareFn1.java +++ /dev/null @@ -1,55 +0,0 @@ -package testsupport; - -import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.monad.Monad; - -import java.util.function.Function; - -import static java.util.Objects.hash; - -public final class EqualityAwareFn1 implements Fn1 { - private final A a; - private final Fn1 fn; - - public EqualityAwareFn1(A a, Fn1 fn) { - this.a = a; - this.fn = fn; - } - - @Override - public B apply(A a) { - return fn.apply(a); - } - - @Override - public EqualityAwareFn1 flatMap(Function>> f) { - return new EqualityAwareFn1<>(a, fn.flatMap(f)); - } - - @Override - public EqualityAwareFn1 fmap(Function f) { - return new EqualityAwareFn1<>(a, fn.fmap(f)); - } - - @Override - public EqualityAwareFn1 zip(Applicative, Fn1> appFn) { - return new EqualityAwareFn1<>(a, fn.zip(appFn)); - } - - @Override - public EqualityAwareFn1 pure(C c) { - return new EqualityAwareFn1<>(a, fn.pure(c)); - } - - @Override - @SuppressWarnings("unchecked") - public boolean equals(Object other) { - return other instanceof Fn1 && ((Fn1) other).apply(a).equals(apply(a)); - } - - @Override - public int hashCode() { - return hash(a, fn); - } -} diff --git a/src/test/java/testsupport/EqualityAwareIO.java b/src/test/java/testsupport/EqualityAwareIO.java deleted file mode 100644 index 822cfebf7..000000000 --- a/src/test/java/testsupport/EqualityAwareIO.java +++ /dev/null @@ -1,64 +0,0 @@ -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); - } -} diff --git a/src/test/java/testsupport/EqualityAwareIso.java b/src/test/java/testsupport/EqualityAwareIso.java deleted file mode 100644 index 0efc7f039..000000000 --- a/src/test/java/testsupport/EqualityAwareIso.java +++ /dev/null @@ -1,72 +0,0 @@ -package testsupport; - -import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.functor.Functor; -import com.jnape.palatable.lambda.functor.Profunctor; -import com.jnape.palatable.lambda.lens.Iso; -import com.jnape.palatable.lambda.lens.LensLike; -import com.jnape.palatable.lambda.monad.Monad; - -import java.util.Objects; -import java.util.function.Function; - -import static com.jnape.palatable.lambda.functions.builtin.fn2.Both.both; -import static com.jnape.palatable.lambda.lens.functions.View.view; - -public final class EqualityAwareIso implements Iso { - private final S s; - private final B b; - private final Iso iso; - - public EqualityAwareIso(S s, B b, Iso iso) { - this.s = s; - this.b = b; - this.iso = iso; - } - - @Override - public

, FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply( - PAFB pafb) { - return iso.apply(pafb); - } - - @Override - public , FB extends Functor> FT apply( - Function fn, S s) { - return iso.apply(fn, s); - } - - @Override - public EqualityAwareIso fmap(Function fn) { - return new EqualityAwareIso<>(s, b, iso.fmap(fn)); - } - - @Override - public EqualityAwareIso pure(U u) { - return new EqualityAwareIso<>(s, b, iso.pure(u)); - } - - @Override - public EqualityAwareIso zip( - Applicative, LensLike> appFn) { - return new EqualityAwareIso<>(s, b, iso.zip(appFn)); - } - - @Override - public EqualityAwareIso flatMap( - Function>> fn) { - return new EqualityAwareIso<>(s, b, iso.flatMap(fn)); - } - - @Override - @SuppressWarnings("unchecked") - public boolean equals(Object other) { - if (other instanceof EqualityAwareIso) { - Iso that = (EqualityAwareIso) other; - Boolean sameForward = both(view(this), view(that)).apply(s).into(Objects::equals); - Boolean sameReverse = both(view(this.mirror()), view(that.mirror())).apply(b).into(Objects::equals); - return sameForward && sameReverse; - } - return false; - } -} diff --git a/src/test/java/testsupport/EqualityAwareLens.java b/src/test/java/testsupport/EqualityAwareLens.java deleted file mode 100644 index e8a8cb52f..000000000 --- a/src/test/java/testsupport/EqualityAwareLens.java +++ /dev/null @@ -1,57 +0,0 @@ -package testsupport; - -import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.functor.Functor; -import com.jnape.palatable.lambda.functor.builtin.Const; -import com.jnape.palatable.lambda.lens.Lens; -import com.jnape.palatable.lambda.lens.LensLike; -import com.jnape.palatable.lambda.monad.Monad; - -import java.util.Objects; -import java.util.function.Function; - -public final class EqualityAwareLens implements Lens { - private final S s; - private final Lens lens; - - public EqualityAwareLens(S s, Lens lens) { - this.s = s; - this.lens = lens; - } - - @Override - public , FB extends Functor> FT apply( - Function fn, S s) { - return lens.apply(fn, s); - } - - @Override - public EqualityAwareLens flatMap( - Function>> f) { - return new EqualityAwareLens<>(s, lens.flatMap(f)); - } - - @Override - public EqualityAwareLens fmap(Function fn) { - return new EqualityAwareLens<>(s, lens.fmap(fn)); - } - - @Override - public EqualityAwareLens pure(U u) { - return new EqualityAwareLens<>(s, lens.pure(u)); - } - - @Override - public EqualityAwareLens zip( - Applicative, LensLike> appFn) { - return new EqualityAwareLens<>(s, lens.zip(appFn)); - } - - @Override - @SuppressWarnings("unchecked") - public boolean equals(Object other) { - return other instanceof Lens - && Objects.equals(((Lens) other)., Const, Const>apply(Const::new, s).runConst(), - this., Const, Const>apply(Const::new, s).runConst()); - } -} diff --git a/src/test/java/testsupport/EquatableM.java b/src/test/java/testsupport/EquatableM.java new file mode 100644 index 000000000..a046e3fa6 --- /dev/null +++ b/src/test/java/testsupport/EquatableM.java @@ -0,0 +1,63 @@ +package testsupport; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.monad.Monad; + +import java.util.Objects; + +public final class EquatableM, A> implements Monad> { + + private final Monad ma; + private final Fn1 equatable; + + public EquatableM(Monad ma, Fn1 equatable) { + this.ma = ma; + this.equatable = equatable; + } + + @Override + public EquatableM flatMap(Fn1>> f) { + return new EquatableM<>(ma.flatMap(f.fmap(x -> x.>coerce().ma)), equatable); + } + + @Override + public EquatableM pure(B b) { + return new EquatableM<>(ma.pure(b), equatable); + } + + @Override + public EquatableM fmap(Fn1 fn) { + return new EquatableM<>(ma.fmap(fn), equatable); + } + + @Override + public EquatableM zip(Applicative, EquatableM> appFn) { + return new EquatableM<>(ma.zip(appFn.>>coerce().ma), equatable); + } + + @Override + public EquatableM discardL(Applicative> appB) { + return new EquatableM<>(ma.discardL(appB.>coerce().ma), equatable); + } + + @Override + public EquatableM discardR(Applicative> appB) { + return new EquatableM<>(ma.discardR(appB.>coerce().ma), equatable); + } + + @Override + @SuppressWarnings("unchecked") + public boolean equals(Object other) { + if (other instanceof EquatableM) { + EquatableM that = (EquatableM) other; + return Objects.equals(equatable.apply((M) ma), that.equatable.apply((M) that.ma)); + } + return false; + } + + @Override + public int hashCode() { + return super.hashCode(); + } +} diff --git a/src/test/java/testsupport/Mocking.java b/src/test/java/testsupport/Mocking.java index 041105a7b..cbc86cd7a 100644 --- a/src/test/java/testsupport/Mocking.java +++ b/src/test/java/testsupport/Mocking.java @@ -18,8 +18,9 @@ public static Iterable mockIterable() { } @SafeVarargs - public static void mockIteratorToHaveValues(Iterator iterator, T... values) { - Iterator real = asList(values).iterator(); + @SuppressWarnings("varargs") + public static void mockIteratorToHaveValues(Iterator iterator, T... values) { + Iterator real = asList(values).iterator(); when(iterator.hasNext()).then(delegateTo(real)); when(iterator.next()).then(delegateTo(real)); diff --git a/src/test/java/testsupport/applicatives/InvocationRecordingBifunctor.java b/src/test/java/testsupport/applicatives/InvocationRecordingBifunctor.java index e1ab75465..a39803ee1 100644 --- a/src/test/java/testsupport/applicatives/InvocationRecordingBifunctor.java +++ b/src/test/java/testsupport/applicatives/InvocationRecordingBifunctor.java @@ -1,24 +1,24 @@ package testsupport.applicatives; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Bifunctor; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Function; -public final class InvocationRecordingBifunctor implements Bifunctor { - private final AtomicReference leftFn; - private final AtomicReference rightFn; +public final class InvocationRecordingBifunctor implements Bifunctor> { + private final AtomicReference> leftFn; + private final AtomicReference> rightFn; - public InvocationRecordingBifunctor(AtomicReference leftFn, - AtomicReference rightFn) { + public InvocationRecordingBifunctor(AtomicReference> leftFn, + AtomicReference> rightFn) { this.leftFn = leftFn; this.rightFn = rightFn; } @Override @SuppressWarnings("unchecked") - public InvocationRecordingBifunctor biMap(Function lFn, - Function rFn) { + public InvocationRecordingBifunctor biMap(Fn1 lFn, + Fn1 rFn) { leftFn.set(lFn); rightFn.set(rFn); return (InvocationRecordingBifunctor) this; diff --git a/src/test/java/testsupport/applicatives/InvocationRecordingProfunctor.java b/src/test/java/testsupport/applicatives/InvocationRecordingProfunctor.java index 4f440bb38..403dee83c 100644 --- a/src/test/java/testsupport/applicatives/InvocationRecordingProfunctor.java +++ b/src/test/java/testsupport/applicatives/InvocationRecordingProfunctor.java @@ -1,24 +1,24 @@ package testsupport.applicatives; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Profunctor; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Function; -public final class InvocationRecordingProfunctor implements Profunctor { - private final AtomicReference leftFn; - private final AtomicReference rightFn; +public final class InvocationRecordingProfunctor implements Profunctor> { + private final AtomicReference> leftFn; + private final AtomicReference> rightFn; - public InvocationRecordingProfunctor(AtomicReference leftFn, - AtomicReference rightFn) { + public InvocationRecordingProfunctor(AtomicReference> leftFn, + AtomicReference> rightFn) { this.leftFn = leftFn; this.rightFn = rightFn; } @Override @SuppressWarnings("unchecked") - public InvocationRecordingProfunctor diMap(Function lFn, - Function rFn) { + public InvocationRecordingProfunctor diMap(Fn1 lFn, + Fn1 rFn) { leftFn.set(lFn); rightFn.set(rFn); return (InvocationRecordingProfunctor) this; diff --git a/src/test/java/testsupport/assertion/LensAssert.java b/src/test/java/testsupport/assertion/LensAssert.java index e89678afb..2c174cada 100644 --- a/src/test/java/testsupport/assertion/LensAssert.java +++ b/src/test/java/testsupport/assertion/LensAssert.java @@ -2,10 +2,13 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.builtin.fn2.Map; -import com.jnape.palatable.lambda.lens.LensLike; +import com.jnape.palatable.lambda.functor.Functor; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monoid.builtin.Present; +import com.jnape.palatable.lambda.optics.Optic; import java.util.Objects; @@ -15,21 +18,23 @@ import static com.jnape.palatable.lambda.functions.builtin.fn2.CartesianProduct.cartesianProduct; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; import static com.jnape.palatable.lambda.functions.builtin.fn2.ReduceLeft.reduceLeft; -import static com.jnape.palatable.lambda.lens.functions.Set.set; -import static com.jnape.palatable.lambda.lens.functions.View.view; +import static com.jnape.palatable.lambda.optics.functions.Set.set; +import static com.jnape.palatable.lambda.optics.functions.View.view; import static java.lang.String.format; import static java.lang.String.join; import static java.util.Arrays.asList; public final class LensAssert { - public static void assertLensLawfulness(LensLike lens, Iterable ss, Iterable bs) { + public static void assertLensLawfulness(Optic, Functor, S, S, A, A> lens, + Iterable ss, + Iterable bs) { Iterable> cases = cartesianProduct(ss, bs); Present.present((x, y) -> join("\n\n", x, y)) .reduceLeft(asList(falsify("You get back what you put in", (s, b) -> view(lens, set(lens, b, s)), (s, b) -> b, cases), falsify("Putting back what you got changes nothing", (s, b) -> set(lens, view(lens, s), s), (s, b) -> s, cases), falsify("Setting twice is equivalent to setting once", (s, b) -> set(lens, b, set(lens, b, s)), (s, b) -> set(lens, b, s), cases))) - .peek(failures -> {throw new AssertionError("Lens law failures\n\n" + failures);}); + .peek(failures -> IO.throwing(new AssertionError("Lens law failures\n\n" + failures))); } private static Maybe falsify(String label, Fn2 l, Fn2 r, diff --git a/src/test/java/testsupport/assertion/PrismAssert.java b/src/test/java/testsupport/assertion/PrismAssert.java new file mode 100644 index 000000000..9794678de --- /dev/null +++ b/src/test/java/testsupport/assertion/PrismAssert.java @@ -0,0 +1,86 @@ +package testsupport.assertion; + +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functions.builtin.fn2.Map; +import com.jnape.palatable.lambda.io.IO; +import com.jnape.palatable.lambda.monoid.builtin.Present; +import com.jnape.palatable.lambda.optics.Prism; + +import java.util.Objects; + +import static com.jnape.palatable.lambda.adt.Either.left; +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.functions.Fn2.fn2; +import static com.jnape.palatable.lambda.functions.builtin.fn1.CatMaybes.catMaybes; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn2.CartesianProduct.cartesianProduct; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; +import static com.jnape.palatable.lambda.functions.builtin.fn2.ReduceLeft.reduceLeft; +import static com.jnape.palatable.lambda.optics.functions.Matching.matching; +import static com.jnape.palatable.lambda.optics.functions.Pre.pre; +import static com.jnape.palatable.lambda.optics.functions.Re.re; +import static com.jnape.palatable.lambda.optics.functions.View.view; +import static java.lang.String.format; +import static java.lang.String.join; +import static java.util.Arrays.asList; + +public final class PrismAssert { + + public static void assertPrismLawfulness(Prism prism, + Iterable ss, + Iterable bs) { + Iterable> cases = cartesianProduct(ss, bs); + Present.present((x, y) -> join("\n\n", x, y)) + .reduceLeft(asList(falsify("The result of a review can always be successfully previewed:", + (s, b) -> view(pre(prism), view(re(prism), b)), (s, b) -> just(b), cases), + falsify("If I can preview a value from an input, I can review the input to the value", + (s, b) -> new PrismResult<>(view(pre(prism), s).fmap(constantly(s))), + (s, b) -> new PrismResult<>(just(view(re(prism), b))), cases), + falsify("A non-match result can always be converted back to an input", + (s, b) -> new PrismResult<>(matching(prism, s).projectA().fmap(matching(prism))), + (s, b) -> new PrismResult<>(just(left(s))), cases))) + .peek(failures -> IO.throwing(new AssertionError("Lens law failures\n\n" + failures))); + } + + private static Maybe falsify(String label, Fn2 l, Fn2 r, + Iterable> cases) { + return Map., Maybe>map(into((s, b) -> { + X x = l.apply(s, b); + X y = r.apply(s, b); + return Objects.equals(x, y) ? nothing() : just(format("S <%s>, B <%s> (%s != %s)", s, b, x, y)); + })) + .fmap(catMaybes()) + .fmap(reduceLeft((x, y) -> x + "\n\t - " + y)) + .fmap(maybeFailures -> maybeFailures.fmap(failures -> "\"" + label + "\" failed for the following cases:\n\n\t - " + failures)) + .apply(cases); + } + + private static final class PrismResult { + private final Maybe maybeS; + + private PrismResult(Maybe maybeS) { + this.maybeS = maybeS; + } + + @Override + public boolean equals(Object other) { + if (other instanceof PrismResult) { + return maybeS.zip(((PrismResult) other).maybeS.fmap(fn2(Objects::equals))).orElse(true); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(maybeS); + } + + @Override + public String toString() { + return maybeS.toString(); + } + } +} diff --git a/src/test/java/testsupport/exceptions/OutOfScopeException.java b/src/test/java/testsupport/exceptions/OutOfScopeException.java index b723b7d4c..8e8f0e4b6 100644 --- a/src/test/java/testsupport/exceptions/OutOfScopeException.java +++ b/src/test/java/testsupport/exceptions/OutOfScopeException.java @@ -1,5 +1,6 @@ package testsupport.exceptions; +@SuppressWarnings("serial") public class OutOfScopeException extends RuntimeException { public OutOfScopeException(String s) { diff --git a/src/test/java/testsupport/functions/ExplainFold.java b/src/test/java/testsupport/functions/ExplainFold.java index a168674e3..d59a2378b 100644 --- a/src/test/java/testsupport/functions/ExplainFold.java +++ b/src/test/java/testsupport/functions/ExplainFold.java @@ -1,12 +1,12 @@ package testsupport.functions; -import java.util.function.BiFunction; +import com.jnape.palatable.lambda.functions.Fn2; import static java.lang.String.format; public class ExplainFold { - public static BiFunction explainFold() { + public static Fn2 explainFold() { return (acc, x) -> format("(%s + %s)", acc, x); } } diff --git a/src/test/java/testsupport/matchers/FiniteIterableMatcher.java b/src/test/java/testsupport/matchers/FiniteIterableMatcher.java index 609f54d51..7f5b57d58 100644 --- a/src/test/java/testsupport/matchers/FiniteIterableMatcher.java +++ b/src/test/java/testsupport/matchers/FiniteIterableMatcher.java @@ -3,7 +3,7 @@ import org.hamcrest.BaseMatcher; import org.hamcrest.Description; -public class FiniteIterableMatcher extends BaseMatcher { +public class FiniteIterableMatcher extends BaseMatcher> { @Override public boolean matches(Object item) { @@ -21,7 +21,7 @@ public void describeMismatch(Object item, Description description) { } @SuppressWarnings("UnusedDeclaration") - private boolean supportsLessThanInfiniteIterations(Iterable iterable) { + private boolean supportsLessThanInfiniteIterations(Iterable iterable) { long sufficientlyInfinite = 1000000; long elementsIterated = 0; for (Object ignored : iterable) diff --git a/src/test/java/testsupport/matchers/IterableMatcher.java b/src/test/java/testsupport/matchers/IterableMatcher.java index 5313e70af..f5f196aba 100644 --- a/src/test/java/testsupport/matchers/IterableMatcher.java +++ b/src/test/java/testsupport/matchers/IterableMatcher.java @@ -5,9 +5,9 @@ import java.util.ArrayList; import java.util.Iterator; +import java.util.Objects; import static java.util.Arrays.asList; -import static org.apache.commons.lang3.builder.EqualsBuilder.reflectionEquals; public class IterableMatcher extends BaseMatcher> { @@ -37,27 +37,27 @@ public void describeMismatch(Object item, Description description) { super.describeMismatch(item, description); } - private boolean iterablesIterateSameElementsInOrder(Iterable expected, Iterable actual) { - Iterator actualIterator = actual.iterator(); - Iterator expectedIterator = expected.iterator(); + private boolean iterablesIterateSameElementsInOrder(Iterable expected, Iterable actual) { + Iterator actualIterator = actual.iterator(); + Iterator expectedIterator = expected.iterator(); while (expectedIterator.hasNext() && actualIterator.hasNext()) { Object nextExpected = expectedIterator.next(); Object nextActual = actualIterator.next(); if (nextExpected instanceof Iterable && nextActual instanceof Iterable) { - if (!iterablesIterateSameElementsInOrder((Iterable) nextExpected, (Iterable) nextActual)) + if (!iterablesIterateSameElementsInOrder((Iterable) nextExpected, (Iterable) nextActual)) return false; - } else if (!reflectionEquals(nextExpected, nextActual)) + } else if (!Objects.equals(nextExpected, nextActual)) return false; } return actualIterator.hasNext() == expectedIterator.hasNext(); } - private String stringify(Iterable iterable) { + private String stringify(Iterable iterable) { StringBuilder stringBuilder = new StringBuilder().append("["); - Iterator iterator = iterable.iterator(); + Iterator iterator = iterable.iterator(); while (iterator.hasNext()) { Object next = iterator.next(); if (next instanceof Iterable) @@ -71,6 +71,7 @@ private String stringify(Iterable iterable) { } @SafeVarargs + @SuppressWarnings("varargs") public static IterableMatcher iterates(E... es) { return new IterableMatcher<>(asList(es)); } diff --git a/src/test/java/testsupport/matchers/LeftMatcher.java b/src/test/java/testsupport/matchers/LeftMatcher.java index 7982965a8..fa57261fe 100644 --- a/src/test/java/testsupport/matchers/LeftMatcher.java +++ b/src/test/java/testsupport/matchers/LeftMatcher.java @@ -6,6 +6,7 @@ import org.hamcrest.TypeSafeMatcher; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.io.IO.io; public final class LeftMatcher extends TypeSafeMatcher> { @@ -29,11 +30,11 @@ public void describeTo(Description description) { @Override protected void describeMismatchSafely(Either item, Description mismatchDescription) { mismatchDescription.appendText("was "); - item.peek(l -> { + item.peek(l -> io(() -> { mismatchDescription.appendText("Left value of "); lMatcher.describeMismatch(l, mismatchDescription); - }, - r -> mismatchDescription.appendValue(item)); + }), + r -> io(() -> mismatchDescription.appendValue(item))); } public static LeftMatcher isLeftThat(Matcher lMatcher) { diff --git a/src/test/java/testsupport/matchers/LensMatcher.java b/src/test/java/testsupport/matchers/LensMatcher.java deleted file mode 100644 index c25f1fa86..000000000 --- a/src/test/java/testsupport/matchers/LensMatcher.java +++ /dev/null @@ -1,59 +0,0 @@ -package testsupport.matchers; - -import com.jnape.palatable.lambda.adt.hlist.Tuple2; -import com.jnape.palatable.lambda.lens.Lens; -import org.hamcrest.BaseMatcher; -import org.hamcrest.Description; - -import java.util.HashSet; - -import static com.jnape.palatable.lambda.functions.builtin.fn1.Empty.empty; -import static com.jnape.palatable.lambda.functions.builtin.fn2.All.all; -import static com.jnape.palatable.lambda.functions.builtin.fn2.CartesianProduct.cartesianProduct; -import static com.jnape.palatable.lambda.functions.builtin.fn2.Filter.filter; -import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; -import static com.jnape.palatable.lambda.functions.builtin.fn2.ToCollection.toCollection; -import static com.jnape.palatable.lambda.lens.functions.Set.set; -import static com.jnape.palatable.lambda.lens.functions.View.view; - -public class LensMatcher extends BaseMatcher> { - - private final Iterable> combinations; - - private LensMatcher(Iterable> combinations) { - this.combinations = combinations; - } - - @Override - @SuppressWarnings("unchecked") - public boolean matches(Object other) { - if (!(other instanceof Lens)) - return false; - - Lens lens = (Lens) other; - return youGetBackWhatYouPutIn(lens) - && puttingBackWhatYouGotChangesNothing(lens) - && settingTwiceIsEquivalentToSettingOnce(lens); - } - - @Override - public void describeTo(Description description) { - throw new UnsupportedOperationException(); - } - - private boolean youGetBackWhatYouPutIn(Lens lens) { - return all(into((s, b) -> view(lens, set(lens, b, s)).equals(b)), combinations); - } - - private boolean puttingBackWhatYouGotChangesNothing(Lens lens) { - return all(into((s, b) -> set(lens, view(lens, s), s).equals(s)), combinations); - } - - private boolean settingTwiceIsEquivalentToSettingOnce(Lens lens) { - return all(into((s, b) -> set(lens, b, set(lens, b, s)).equals(set(lens, b, s))), combinations); - } - - public static LensMatcher isLawfulForAllSAndB(Iterable ss, Iterable bs) { - return new LensMatcher<>(cartesianProduct(ss, bs)); - } -} diff --git a/src/test/java/testsupport/matchers/RightMatcher.java b/src/test/java/testsupport/matchers/RightMatcher.java index 08965bf2f..cce44fe03 100644 --- a/src/test/java/testsupport/matchers/RightMatcher.java +++ b/src/test/java/testsupport/matchers/RightMatcher.java @@ -6,6 +6,7 @@ import org.hamcrest.TypeSafeMatcher; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.io.IO.io; public final class RightMatcher extends TypeSafeMatcher> { @@ -29,11 +30,11 @@ public void describeTo(Description description) { @Override protected void describeMismatchSafely(Either item, Description mismatchDescription) { mismatchDescription.appendText("was "); - item.peek(l -> mismatchDescription.appendValue(item), - r -> { + item.peek(l -> io(() -> mismatchDescription.appendValue(item)), + r -> io(() -> { mismatchDescription.appendText("Right value of "); rMatcher.describeMismatch(r, mismatchDescription); - }); + })); } public static RightMatcher isRightThat(Matcher rMatcher) { diff --git a/src/test/java/testsupport/traits/ApplicativeLaws.java b/src/test/java/testsupport/traits/ApplicativeLaws.java index 6255798ce..1d5c0904f 100644 --- a/src/test/java/testsupport/traits/ApplicativeLaws.java +++ b/src/test/java/testsupport/traits/ApplicativeLaws.java @@ -1,91 +1,94 @@ package testsupport.traits; import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monoid.builtin.Present; import com.jnape.palatable.traitor.traits.Trait; import java.util.Random; -import java.util.function.Function; import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static java.util.Arrays.asList; -import static java.util.function.Function.identity; -public class ApplicativeLaws implements Trait> { +public class ApplicativeLaws> implements Trait> { @Override public void test(Applicative applicative) { Present.present((x, y) -> x + "\n\t - " + y) - ., Maybe>>foldMap( + ., Maybe>>foldMap( f -> f.apply(applicative), asList(this::testIdentity, this::testComposition, this::testHomomorphism, this::testInterchange, this::testDiscardL, - this::testDiscardR) + this::testDiscardR, + this::testLazyZip) ) - .peek(s -> { - throw new AssertionError("The following Applicative laws did not hold for instance of " + applicative.getClass() + ": \n\t - " + s); - }); + .peek(s -> IO.throwing(new AssertionError("The following Applicative laws did not hold for instance of " + + applicative.getClass() + ": \n\t - " + s))); } private Maybe testIdentity(Applicative applicative) { - Applicative v = applicative.pure(1); - Applicative, App> pureId = v.pure(identity()); + Applicative v = applicative.pure(1); + Applicative, App> pureId = v.pure(id()); return v.zip(pureId).equals(v) - ? nothing() - : just("identity (v.zip(pureId).equals(v))"); + ? nothing() + : just("identity (v.zip(pureId).equals(v))"); } private Maybe testComposition(Applicative applicative) { - Random random = new Random(); - Integer firstInt = random.nextInt(100); + Random random = new Random(); + Integer firstInt = random.nextInt(100); Integer secondInt = random.nextInt(100); - Function, ? extends Function, ? extends Function>> compose = x -> x::compose; - Applicative, App> u = applicative.pure(x -> x + firstInt); - Applicative, App> v = applicative.pure(x -> x + secondInt); - Applicative w = applicative.pure("result: "); + Fn1, + Fn1, + Fn1>> compose = x -> x::contraMap; + Applicative, App> u = applicative.pure(x -> x + firstInt); + Applicative, App> v = applicative.pure(x -> x + secondInt); + Applicative w = applicative.pure("result: "); - Applicative, ? extends Function, ? extends Function>>, App> pureCompose = u.pure(compose); - return w.zip(v.zip(u.zip(pureCompose))).equals(w.zip(v).zip(u)) - ? nothing() - : just("composition (w.zip(v.zip(u.zip(pureCompose))).equals((w.zip(v)).zip(u)))"); + return w.zip(v.zip(u.zip(u.pure(compose)))).equals(w.zip(v).zip(u)) + ? nothing() + : just("composition (w.zip(v.zip(u.zip(pureCompose))).equals((w.zip(v)).zip(u)))"); } private Maybe testHomomorphism(Applicative applicative) { - Function f = x -> x + 1; - int x = 1; + Fn1 f = x -> x + 1; + int x = 1; - Applicative pureX = applicative.pure(x); - Applicative, App> pureF = applicative.pure(f); - Applicative pureFx = applicative.pure(f.apply(x)); + Applicative pureX = applicative.pure(x); + Applicative, App> pureF = applicative.pure(f); + Applicative pureFx = applicative.pure(f.apply(x)); return pureX.zip(pureF).equals(pureFx) - ? nothing() - : just("homomorphism (pureX.zip(pureF).equals(pureFx))"); + ? nothing() + : just("homomorphism (pureX.zip(pureF).equals(pureFx))"); } private Maybe testInterchange(Applicative applicative) { - Applicative, App> u = applicative.pure(x -> x + 1); - int y = 1; + Applicative, App> u = applicative.pure(x -> x + 1); + int y = 1; Applicative pureY = applicative.pure(y); return pureY.zip(u).equals(u.zip(applicative.pure(f -> f.apply(y)))) - ? nothing() - : just("interchange (pureY.zip(u).equals(u.zip(applicative.pure(f -> f.apply(y)))))"); + ? nothing() + : just("interchange (pureY.zip(u).equals(u.zip(applicative.pure(f -> f.apply(y)))))"); } private Maybe testDiscardL(Applicative applicative) { Applicative u = applicative.pure("u"); Applicative v = applicative.pure("v"); - return u.discardL(v).equals(v.zip(u.zip(applicative.pure(constantly(identity()))))) - ? nothing() - : just("discardL u.discardL(v).equals(v.zip(u.zip(applicative.pure(constantly(identity())))))"); + return u.discardL(v).equals(v.zip(u.zip(applicative.pure(constantly(id()))))) + ? nothing() + : just("discardL u.discardL(v).equals(v.zip(u.zip(applicative.pure(constantly(identity())))))"); } private Maybe testDiscardR(Applicative applicative) { @@ -93,7 +96,13 @@ private Maybe testDiscardR(Applicative applicative) { Applicative v = applicative.pure("v"); return u.discardR(v).equals(v.zip(u.zip(applicative.pure(constantly())))) - ? nothing() - : just("discardR u.discardR(v).equals(v.zip(u.zip(applicative.pure(constantly()))))"); + ? nothing() + : just("discardR u.discardR(v).equals(v.zip(u.zip(applicative.pure(constantly()))))"); + } + + private Maybe testLazyZip(Applicative applicative) { + return applicative.lazyZip(lazy(applicative.pure(id()))).value().equals(applicative.zip(applicative.pure(id()))) + ? nothing() + : just("lazyZip app.zip(lazy(app.pure(id()))).equals(app.zip(app.pure(id())))"); } } diff --git a/src/test/java/testsupport/traits/BifunctorLaws.java b/src/test/java/testsupport/traits/BifunctorLaws.java index b8bb42856..d682435e6 100644 --- a/src/test/java/testsupport/traits/BifunctorLaws.java +++ b/src/test/java/testsupport/traits/BifunctorLaws.java @@ -1,48 +1,47 @@ package testsupport.traits; import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monoid.builtin.Present; import com.jnape.palatable.traitor.traits.Trait; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static java.util.Arrays.asList; -public class BifunctorLaws implements Trait> { +public class BifunctorLaws> implements Trait> { @Override public void test(Bifunctor bifunctor) { Present.present((x, y) -> x + "\n\t - " + y) - ., Maybe>>foldMap( + ., Maybe>>foldMap( f -> f.apply(bifunctor), asList(this::testLeftIdentity, this::testRightIdentity, this::testMutualIdentity) ) - .peek(s -> { - throw new AssertionError("The following Bifunctor laws did not hold for instance of " + bifunctor.getClass() + ": \n\t - " + s); - }); + .peek(s -> IO.throwing(new AssertionError("The following Bifunctor laws did not hold for instance of " + + bifunctor.getClass() + ": \n\t - " + s))); } private Maybe testLeftIdentity(Bifunctor bifunctor) { return bifunctor.biMapL(id()).equals(bifunctor) - ? nothing() - : just("left identity (bifunctor.biMapL(id()).equals(bifunctor))"); + ? nothing() + : just("left identity (bifunctor.biMapL(id()).equals(bifunctor))"); } private Maybe testRightIdentity(Bifunctor bifunctor) { return bifunctor.biMapR(id()).equals(bifunctor) - ? nothing() - : just("right identity (bifunctor.biMapR(id()).equals(bifunctor))"); + ? nothing() + : just("right identity (bifunctor.biMapR(id()).equals(bifunctor))"); } private Maybe testMutualIdentity(Bifunctor bifunctor) { return bifunctor.biMapL(id()).biMapR(id()).equals(bifunctor.biMap(id(), id())) - ? nothing() - : just("mutual identity (bifunctor.biMapL(id()).biMapR(id()).equals(bifunctor.biMap(id(),id()))"); + ? nothing() + : just("mutual identity (bifunctor.biMapL(id()).biMapR(id()).equals(bifunctor.biMap(id(),id()))"); } } diff --git a/src/test/java/testsupport/traits/EmptyIterableSupport.java b/src/test/java/testsupport/traits/EmptyIterableSupport.java index a0d2d029a..d30b57a3e 100644 --- a/src/test/java/testsupport/traits/EmptyIterableSupport.java +++ b/src/test/java/testsupport/traits/EmptyIterableSupport.java @@ -5,12 +5,12 @@ import java.util.ArrayList; -public class EmptyIterableSupport implements Trait> { +public class EmptyIterableSupport implements Trait, ?>> { @Override - public void test(Fn1 testSubject) { + public void test(Fn1, ?> testSubject) { try { - testSubject.apply(new ArrayList()); + testSubject.apply(new ArrayList<>()); } catch (Exception e) { throw new AssertionError("Expected support for empty iterable arguments", e); } diff --git a/src/test/java/testsupport/traits/FiniteIteration.java b/src/test/java/testsupport/traits/FiniteIteration.java index 882632f17..03168d2b6 100644 --- a/src/test/java/testsupport/traits/FiniteIteration.java +++ b/src/test/java/testsupport/traits/FiniteIteration.java @@ -8,11 +8,11 @@ import static org.hamcrest.core.Is.is; import static testsupport.matchers.FiniteIterableMatcher.finitelyIterable; -public class FiniteIteration implements Trait> { +public class FiniteIteration implements Trait, Iterable>> { @Override - public void test(Fn1 testSubject) { - Iterable result = testSubject.apply(asList(1, 2, 3)); + public void test(Fn1, Iterable> testSubject) { + Iterable result = testSubject.apply(asList(1, 2, 3)); assertThat(result, is(finitelyIterable())); } } diff --git a/src/test/java/testsupport/traits/FunctorLaws.java b/src/test/java/testsupport/traits/FunctorLaws.java index a6b5f3d0e..5fc7d5937 100644 --- a/src/test/java/testsupport/traits/FunctorLaws.java +++ b/src/test/java/testsupport/traits/FunctorLaws.java @@ -1,44 +1,43 @@ package testsupport.traits; import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Functor; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monoid.builtin.Present; import com.jnape.palatable.traitor.traits.Trait; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static java.util.Arrays.asList; -import static java.util.function.Function.identity; -public class FunctorLaws implements Trait> { +public class FunctorLaws> implements Trait> { @Override public void test(Functor f) { Present.present((x, y) -> x + "\n\t - " + y) - ., Maybe>>foldMap( + ., Maybe>>foldMap( fn -> fn.apply(f), asList(this::testIdentity, this::testComposition)) - .peek(s -> { - throw new AssertionError("The following Functor laws did not hold for instance of " + f.getClass() + ": \n\t - " + s); - }); + .peek(s -> IO.throwing(new AssertionError("The following Functor laws did not hold for instance of " + + f.getClass() + ": \n\t - " + s))); } private Maybe testIdentity(Functor f) { - return f.fmap(identity()).equals(f) - ? nothing() - : just("identity (f.fmap(identity()).equals(f))"); + return f.fmap(id()).equals(f) + ? nothing() + : just("identity (f.fmap(identity()).equals(f))"); } private Maybe testComposition(Functor functor) { - Functor subject = functor.fmap(constantly(1)); - Function f = x -> x * 3; - Function g = x -> x - 2; - return subject.fmap(f.compose(g)).equals(subject.fmap(g).fmap(f)) - ? nothing() - : just("composition (functor.fmap(f.compose(g)).equals(functor.fmap(g).fmap(f)))"); + Functor subject = functor.fmap(constantly(1)); + Fn1 f = x -> x * 3; + Fn1 g = x -> x - 2; + return subject.fmap(f.contraMap(g)).equals(subject.fmap(g).fmap(f)) + ? nothing() + : just("composition (functor.fmap(f.contraMap(g)).equals(functor.fmap(g).fmap(f)))"); } } diff --git a/src/test/java/testsupport/traits/ImmutableIteration.java b/src/test/java/testsupport/traits/ImmutableIteration.java index ce6e7db55..d6a74737e 100644 --- a/src/test/java/testsupport/traits/ImmutableIteration.java +++ b/src/test/java/testsupport/traits/ImmutableIteration.java @@ -7,11 +7,11 @@ import static org.junit.Assert.fail; -public class ImmutableIteration implements Trait> { +public class ImmutableIteration implements Trait, Iterable>> { @Override - public void test(Fn1 testSubject) { - Iterable result = testSubject.apply(new ArrayList()); + public void test(Fn1, Iterable> testSubject) { + Iterable result = testSubject.apply(new ArrayList<>()); try { result.iterator().remove(); fail("Expected remove() to throw Exception, but it didn't."); diff --git a/src/test/java/testsupport/traits/InfiniteIterableSupport.java b/src/test/java/testsupport/traits/InfiniteIterableSupport.java index 3c870f1ad..3c1131341 100644 --- a/src/test/java/testsupport/traits/InfiniteIterableSupport.java +++ b/src/test/java/testsupport/traits/InfiniteIterableSupport.java @@ -9,10 +9,10 @@ import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.Assert.fail; -public class InfiniteIterableSupport implements Trait> { +public class InfiniteIterableSupport implements Trait, Iterable>> { @Override - public void test(Fn1 testSubject) { + public void test(Fn1, Iterable> testSubject) { CountDownLatch latch = new CountDownLatch(1); new Thread(() -> { testSubject.apply(repeat(0)).iterator().next(); diff --git a/src/test/java/testsupport/traits/InfiniteIteration.java b/src/test/java/testsupport/traits/InfiniteIteration.java index 12072fe78..085907ce2 100644 --- a/src/test/java/testsupport/traits/InfiniteIteration.java +++ b/src/test/java/testsupport/traits/InfiniteIteration.java @@ -9,11 +9,11 @@ import static org.hamcrest.core.Is.is; import static testsupport.matchers.FiniteIterableMatcher.finitelyIterable; -public class InfiniteIteration implements Trait> { +public class InfiniteIteration implements Trait, Iterable>> { @Override - public void test(Fn1 testSubject) { - Iterable result = testSubject.apply(asList(1, 2, 3)); + public void test(Fn1, Iterable> testSubject) { + Iterable result = testSubject.apply(asList(1, 2, 3)); assertThat(result, is(not(finitelyIterable()))); } } diff --git a/src/test/java/testsupport/traits/Laziness.java b/src/test/java/testsupport/traits/Laziness.java index 216201df7..cd0a58b6c 100644 --- a/src/test/java/testsupport/traits/Laziness.java +++ b/src/test/java/testsupport/traits/Laziness.java @@ -7,11 +7,11 @@ import static testsupport.Mocking.mockIterable; import static testsupport.matchers.ZeroInvocationsMatcher.wasNeverInteractedWith; -public class Laziness implements Trait> { +public class Laziness implements Trait, Iterable>> { @Override - public void test(Fn1 testSubject) { - Iterable iterable = mockIterable(); + public void test(Fn1, Iterable> testSubject) { + Iterable iterable = mockIterable(); testSubject.apply(iterable); assertThat(iterable, wasNeverInteractedWith()); diff --git a/src/test/java/testsupport/traits/MonadLaws.java b/src/test/java/testsupport/traits/MonadLaws.java index 038fc6789..2ff5a6e77 100644 --- a/src/test/java/testsupport/traits/MonadLaws.java +++ b/src/test/java/testsupport/traits/MonadLaws.java @@ -2,12 +2,11 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.monoid.builtin.Present; import com.jnape.palatable.traitor.traits.Trait; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; @@ -16,24 +15,23 @@ import static com.jnape.palatable.lambda.monad.Monad.join; import static java.util.Arrays.asList; -public class MonadLaws implements Trait> { +public class MonadLaws> implements Trait> { @Override public void test(Monad m) { Present.present((x, y) -> x + "\n\t - " + y) - ., Maybe>>foldMap(f -> f.apply(m), asList( + ., Maybe>>foldMap(f -> f.apply(m), asList( this::testLeftIdentity, this::testRightIdentity, this::testAssociativity, this::testJoin)) - .peek(s -> { - throw new AssertionError("The following Monad laws did not hold for instance of " + m.getClass() + ": \n\t - " + s); - }); + .peek(s -> IO.throwing(new AssertionError("The following Monad laws did not hold for instance of " + + m.getClass() + ": \n\t - " + s))); } private Maybe testLeftIdentity(Monad m) { - Object a = new Object(); - Fn1> fn = id().andThen(m::pure); + Object a = new Object(); + Fn1> fn = id().fmap(m::pure); return m.pure(a).flatMap(fn).equals(fn.apply(a)) ? nothing() : just("left identity (m.pure(a).flatMap(fn).equals(fn.apply(a)))"); @@ -47,15 +45,15 @@ private Maybe testRightIdentity(Monad m) { private Maybe testAssociativity(Monad m) { Fn1> f = constantly(m.pure(new Object())); - Function> g = constantly(m.pure(new Object())); + Fn1> g = constantly(m.pure(new Object())); return m.flatMap(f).flatMap(g).equals(m.flatMap(a -> f.apply(a).flatMap(g))) ? nothing() : just("associativity: (m.flatMap(f).flatMap(g).equals(m.flatMap(a -> f.apply(a).flatMap(g))))"); } private Maybe testJoin(Monad m) { - Monad, M> mma = m.pure(m.fmap(upcast())); - boolean equals = mma.flatMap(id()).equals(join(mma)); + Monad, M> mma = m.pure(m.fmap(upcast())); + boolean equals = mma.flatMap(id()).equals(join(mma)); return equals ? nothing() : just("join: (m.pure(m).flatMap(id())).equals(Monad.join(m.pure(m)))"); diff --git a/src/test/java/testsupport/traits/TraversableLaws.java b/src/test/java/testsupport/traits/TraversableLaws.java index 8ce0ab0f0..c0a6c4968 100644 --- a/src/test/java/testsupport/traits/TraversableLaws.java +++ b/src/test/java/testsupport/traits/TraversableLaws.java @@ -2,15 +2,15 @@ import com.jnape.palatable.lambda.adt.Either; import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Compose; import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monoid.builtin.Present; import com.jnape.palatable.lambda.traversable.Traversable; import com.jnape.palatable.traitor.traits.Trait; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.Either.right; import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; @@ -18,51 +18,51 @@ import static java.util.Arrays.asList; @SuppressWarnings("Convert2MethodRef") -public class TraversableLaws implements Trait> { +public class TraversableLaws> implements Trait> { @Override public void test(Traversable traversable) { Present.present((x, y) -> x + "\n\t - " + y) - ., Maybe>>foldMap( + ., Maybe>>foldMap( f -> f.apply(traversable), asList(this::testNaturality, this::testIdentity, this::testComposition) ) - .peek(s -> { - throw new AssertionError("The following Traversable laws did not hold for instance of " + traversable.getClass() + ": \n\t - " + s); - }); + .peek(s -> IO.throwing(new AssertionError("The following Traversable laws did not hold for instance of " + + traversable.getClass() + ": \n\t - " + s))); } private Maybe testNaturality(Traversable trav) { - Function> f = Identity::new; - Function, Either> t = id -> right(id.runIdentity()); + Fn1> f = Identity::new; + Fn1, Either> t = id -> right(id.runIdentity()); - Function, Applicative, Identity>> pureFn = x -> new Identity<>(x); - Function, Applicative, Either>> pureFn2 = x -> right(x); + Fn1, Applicative, Identity>> pureFn = + x -> new Identity<>(x); + Fn1, Applicative, Either>> pureFn2 = + x -> right(x); return t.apply(trav.traverse(f, pureFn).fmap(id()).coerce()) - .equals(trav.traverse(t.compose(f), pureFn2).fmap(id()).coerce()) - ? nothing() - : just("naturality (t.apply(trav.traverse(f, pureFn).fmap(id()).coerce())\n" + - " .equals(trav.traverse(t.compose(f), pureFn2).fmap(id()).coerce()))"); + .equals(trav.traverse(t.contraMap(f), pureFn2).fmap(id()).coerce()) + ? nothing() + : just("naturality (t.apply(trav.traverse(f, pureFn).fmap(id()).coerce())\n" + + " .equals(trav.traverse(t.contraMap(f), pureFn2).fmap(id()).coerce()))"); } private Maybe testIdentity(Traversable trav) { return trav.traverse(Identity::new, x -> new Identity<>(x)).equals(new Identity<>(trav)) - ? nothing() - : just("identity (trav.traverse(Identity::new, x -> new Identity<>(x)).equals(new Identity<>(trav))"); + ? nothing() + : just("identity (trav.traverse(Identity::new, x -> new Identity<>(x)).equals(new Identity<>(trav))"); } - @SuppressWarnings("unchecked") private Maybe testComposition(Traversable trav) { - Function> f = Identity::new; - Function> g = x -> new Identity<>(x); + Fn1> f = Identity::new; + Fn1>> g = x -> new Identity<>(x); - return trav.traverse(f.andThen(x -> x.fmap(g)).andThen(Compose::new), x -> new Compose<>(new Identity<>(new Identity<>(x)))) + return trav.traverse(f.fmap(x -> x.fmap(g)).fmap(Compose::new), x -> new Compose<>(new Identity<>(new Identity<>(x)))) .equals(new Compose<>(trav.traverse(f, x -> new Identity<>(x)).fmap(t -> t.traverse(g, x -> new Identity<>(x))))) - ? nothing() - : just("compose (trav.traverse(f.andThen(x -> x.fmap(g)).andThen(Compose::new), x -> new Compose<>(new Identity<>(new Identity<>(x))))\n" + - " .equals(new Compose>(trav.traverse(f, x -> new Identity<>(x)).fmap(t -> t.traverse(g, x -> new Identity<>(x))))))"); + ? nothing() + : just("compose (trav.traverse(f.fmap(x -> x.fmap(g)).fmap(Compose::new), x -> new Compose<>(new Identity<>(new Identity<>(x))))\n" + + " .equals(new Compose>(trav.traverse(f, x -> new Identity<>(x)).fmap(t -> t.traverse(g, x -> new Identity<>(x))))))"); } }

, FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply( + public >, CoF extends Functor>, FB extends Functor, FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply( PAFB pafb) { - return composed.apply(pafb); + return composed.apply(pafb); } @Override @@ -93,6 +94,11 @@ static Simple typeSafeKey() { public boolean equals(Object obj) { return obj instanceof Simple ? this == obj : Objects.equals(obj, this); } + + @Override + public int hashCode() { + return super.hashCode(); + } }; } @@ -105,7 +111,12 @@ interface Simple extends TypeSafeKey { @Override @SuppressWarnings("unchecked") - default