From 8955630a2f1e176b840cdb49294e06adf883f880 Mon Sep 17 00:00:00 2001 From: JesseBrault0709 <62299747+JesseBrault0709@users.noreply.github.com> Date: Mon, 13 May 2024 14:14:21 +0200 Subject: [PATCH] Groowt-all and fp. --- build.gradle | 26 +++ .../java/groowt/util/fp/either/Either.java | 90 ++++++++++ src/main/java/groowt/util/fp/hkt/Monoid.java | 23 +++ .../java/groowt/util/fp/hkt/SemiGroup.java | 17 ++ src/main/java/groowt/util/fp/hkt/Zero.java | 17 ++ .../java/groowt/util/fp/option/Option.java | 159 ++++++++++++++++++ .../groowt/util/fp/property/Property.java | 56 ++++++ .../util/fp/property/SimpleProperty.java | 57 +++++++ .../groowt/util/fp/provider/LazyProvider.java | 18 ++ .../groowt/util/fp/provider/Provider.java | 26 +++ .../util/fp/provider/SimpleProvider.java | 18 ++ 11 files changed, 507 insertions(+) create mode 100644 build.gradle create mode 100644 src/main/java/groowt/util/fp/either/Either.java create mode 100644 src/main/java/groowt/util/fp/hkt/Monoid.java create mode 100644 src/main/java/groowt/util/fp/hkt/SemiGroup.java create mode 100644 src/main/java/groowt/util/fp/hkt/Zero.java create mode 100644 src/main/java/groowt/util/fp/option/Option.java create mode 100644 src/main/java/groowt/util/fp/property/Property.java create mode 100644 src/main/java/groowt/util/fp/property/SimpleProperty.java create mode 100644 src/main/java/groowt/util/fp/provider/LazyProvider.java create mode 100644 src/main/java/groowt/util/fp/provider/Provider.java create mode 100644 src/main/java/groowt/util/fp/provider/SimpleProvider.java diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..97ee98c --- /dev/null +++ b/build.gradle @@ -0,0 +1,26 @@ +plugins { + id 'groowt-conventions' + id 'groowt-publish' + id 'java-library' +} + +repositories { + mavenCentral() +} + +dependencies { + compileOnlyApi libs.jetbrains.anotations +} + +jar { + archiveBaseName = 'groowt-util-fp' +} + +publishing { + publications { + create('fp', MavenPublication) { + artifactId = 'groowt-util-fp' + from components.java + } + } +} diff --git a/src/main/java/groowt/util/fp/either/Either.java b/src/main/java/groowt/util/fp/either/Either.java new file mode 100644 index 0000000..921c0e7 --- /dev/null +++ b/src/main/java/groowt/util/fp/either/Either.java @@ -0,0 +1,90 @@ +package groowt.util.fp.either; + +import java.util.function.Function; + +public sealed interface Either { + + @SuppressWarnings("unchecked") + static Either left(E error) { + return (Either) new Left<>(error); + } + + @SuppressWarnings("unchecked") + static Either right(T item) { + return (Either) new Right<>(item); + } + + final class Left implements Either { + + private final E error; + + public Left(E error) { + this.error = error; + } + + public E get() { + return this.error; + } + + } + + final class Right implements Either { + + private final T item; + + public Right(T item) { + this.item = item; + } + + public T get() { + return this.item; + } + + } + + default boolean isLeft() { + return this instanceof Either.Left; + } + + default boolean isRight() { + return this instanceof Either.Right; + } + + @SuppressWarnings("unchecked") + default Left asLeft() { + return (Left) this; + } + + @SuppressWarnings("unchecked") + default Right asRight() { + return (Right) this; + } + + default E getLeft() { + return this.asLeft().get(); + } + + default T getRight() { + return this.asRight().get(); + } + + @SuppressWarnings("unchecked") + default Either mapLeft(Function onLeft) { + if (this.isLeft()) { + return (Either) new Right<>(onLeft.apply(this.getLeft())); + } else { + return this; + } + } + + @SuppressWarnings("unchecked") + default Either flatMapLeft(Function> onLeft) { + if (this.isLeft()) { + final var error = this.getLeft(); + return (Either) onLeft.apply(error); + } else { + return this; + } + } + +} diff --git a/src/main/java/groowt/util/fp/hkt/Monoid.java b/src/main/java/groowt/util/fp/hkt/Monoid.java new file mode 100644 index 0000000..ce5f1cb --- /dev/null +++ b/src/main/java/groowt/util/fp/hkt/Monoid.java @@ -0,0 +1,23 @@ +package groowt.util.fp.hkt; + +import java.util.Objects; + +public final class Monoid { + + private final SemiGroup semiGroup; + private final Zero zero; + + public Monoid(SemiGroup semiGroup, Zero zero) { + this.semiGroup = Objects.requireNonNull(semiGroup); + this.zero = Objects.requireNonNull(zero); + } + + public T concat(T left, T right) { + return this.semiGroup.concat(left, right); + } + + public T empty() { + return this.zero.getEmpty(); + } + +} diff --git a/src/main/java/groowt/util/fp/hkt/SemiGroup.java b/src/main/java/groowt/util/fp/hkt/SemiGroup.java new file mode 100644 index 0000000..0976caf --- /dev/null +++ b/src/main/java/groowt/util/fp/hkt/SemiGroup.java @@ -0,0 +1,17 @@ +package groowt.util.fp.hkt; + +import java.util.function.BinaryOperator; + +public final class SemiGroup { + + private final BinaryOperator concat; + + public SemiGroup(BinaryOperator concat) { + this.concat = concat; + } + + public T concat(T left, T right) { + return this.concat.apply(left, right); + } + +} diff --git a/src/main/java/groowt/util/fp/hkt/Zero.java b/src/main/java/groowt/util/fp/hkt/Zero.java new file mode 100644 index 0000000..ce35d4b --- /dev/null +++ b/src/main/java/groowt/util/fp/hkt/Zero.java @@ -0,0 +1,17 @@ +package groowt.util.fp.hkt; + +import java.util.Objects; + +public final class Zero { + + private final T empty; + + public Zero(T empty) { + this.empty = Objects.requireNonNull(empty); + } + + public T getEmpty() { + return this.empty; + } + +} diff --git a/src/main/java/groowt/util/fp/option/Option.java b/src/main/java/groowt/util/fp/option/Option.java new file mode 100644 index 0000000..62d354f --- /dev/null +++ b/src/main/java/groowt/util/fp/option/Option.java @@ -0,0 +1,159 @@ +package groowt.util.fp.option; + +import groowt.util.fp.hkt.Monoid; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +public abstract sealed class Option { + + private static EmptyOption emptyInstance; + + public static Option lift(T value) { + return new ValueOption<>(Objects.requireNonNull(value)); + } + + public static Option liftNullable(@Nullable T value) { + return value == null ? empty() : lift(value); + } + + public static Option liftLazy(Supplier valueSupplier) { + return new SupplierOption<>(Objects.requireNonNull(valueSupplier)); + } + + @SuppressWarnings("unchecked") + public static Option empty() { + if (emptyInstance == null) { + emptyInstance = new EmptyOption<>(); + } + return (Option) emptyInstance; + } + + private static final class EmptyOption extends Option { + + @Override + public T get() { + throw new NullPointerException("Cannot get() on EmptyOption"); + } + + @Override + public boolean isPresent() { + return false; + } + + } + + private static final class ValueOption extends Option { + + private final T value; + + public ValueOption(T value) { + this.value = value; + } + + @Override + public T get() { + return this.value; + } + + } + + private static final class SupplierOption extends Option { + + private final Supplier valueSupplier; + + public SupplierOption(Supplier valueSupplier) { + this.valueSupplier = valueSupplier::get; + } + + @Override + public T get() { + return Objects.requireNonNull( + this.valueSupplier.get(), + "Cannot get() when the given valueSupplier returns null." + ); + } + + } + + public abstract T get(); + + public boolean isPresent() { + return true; + } + + public @NotNull T getOrElse(T other) { + return this.isPresent() ? this.get() : Objects.requireNonNull(other); + } + + public @Nullable T getOrElseNull() { + return this.isPresent() ? this.get() : null; + } + + public Option orElseLift(T other) { + return this.isPresent() ? this : new ValueOption<>(Objects.requireNonNull(other)); + } + + public Option orElseLiftLazy(Supplier lazyOther) { + return this.isPresent() ? this : new SupplierOption<>(Objects.requireNonNull(lazyOther)); + } + + public Option map(Function mapper) { + return new SupplierOption<>(() -> mapper.apply(this.get())); + } + + public Option mapLazy(Function> lazyMapper) { + return new SupplierOption<>(() -> lazyMapper.apply(this.get()).get()); + } + + public Option flatMap(Function> mapper) { + return new SupplierOption<>(() -> mapper.apply(this.get()).get()); + } + + public Option flatMapLazy(Function>> lazyMapper) { + return new SupplierOption<>(() -> lazyMapper.apply(this.get()).get().get()); + } + + public void ifPresent(Consumer onPresent) { + if (this.isPresent()) { + onPresent.accept(this.get()); + } + } + + public void ifPresentOrElse(Consumer onPresent, Runnable orElse) { + if (this.isPresent()) { + onPresent.accept(this.get()); + } else { + orElse.run(); + } + } + + public R fold(Function onPresent, Supplier onEmpty) { + if (this.isPresent()) { + return onPresent.apply(this.get()); + } else { + return onEmpty.get(); + } + } + + public R foldMap(Monoid monoid, Function onPresent) { + if (this.isPresent()) { + return onPresent.apply(this.get()); + } else { + return monoid.empty(); + } + } + + public R foldFlatMap(Monoid monoid, Function> onPresent) { + if (this.isPresent()) { + return onPresent.apply(this.get()).get(); + } else { + return monoid.empty(); + } + } + +} diff --git a/src/main/java/groowt/util/fp/property/Property.java b/src/main/java/groowt/util/fp/property/Property.java new file mode 100644 index 0000000..a173ec6 --- /dev/null +++ b/src/main/java/groowt/util/fp/property/Property.java @@ -0,0 +1,56 @@ +package groowt.util.fp.property; + +import groowt.util.fp.provider.Provider; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Supplier; + +public interface Property extends Provider { + + static Property get(Class tClass) { + return new SimpleProperty<>(); + } + + static Property of(T t) { + final Property property = new SimpleProperty<>(); + property.set(t); + return property; + } + + static Property ofLazy(Provider tProvider) { + final Property property = new SimpleProperty<>(); + property.set(tProvider); + return property; + } + + static Property ofLazy(Supplier tSupplier) { + final Property property = new SimpleProperty<>(); + property.set(Provider.ofLazy(tSupplier)); + return property; + } + + void set(T t); + void set(Provider tProvider); + void setConvention(T t); + void setConvention(Provider tProvider); + + boolean isPresent(); + boolean isEmpty(); + + default T fold(@Nullable T onEmpty) { + if (this.isPresent()) { + return this.get(); + } else { + return onEmpty; + } + } + + default T fold(Provider onEmpty) { + if (this.isPresent()) { + return this.get(); + } else { + return onEmpty.get(); + } + } + +} diff --git a/src/main/java/groowt/util/fp/property/SimpleProperty.java b/src/main/java/groowt/util/fp/property/SimpleProperty.java new file mode 100644 index 0000000..69260ec --- /dev/null +++ b/src/main/java/groowt/util/fp/property/SimpleProperty.java @@ -0,0 +1,57 @@ +package groowt.util.fp.property; + +import groowt.util.fp.provider.Provider; + +import java.util.Objects; + +final class SimpleProperty implements Property { + + private Provider provider; + private Provider convention; + + @Override + public boolean isPresent() { + return this.provider != null || this.convention != null; + } + + @Override + public boolean isEmpty() { + return this.provider == null && this.convention == null; + } + + @Override + public void set(T t) { + Objects.requireNonNull(t); + this.provider = Provider.of(t); + } + + @Override + public void set(Provider tProvider) { + Objects.requireNonNull(tProvider); + this.provider = tProvider; + } + + @Override + public void setConvention(T convention) { + Objects.requireNonNull(convention); + this.convention = Provider.of(convention); + } + + @Override + public void setConvention(Provider convention) { + Objects.requireNonNull(convention); + this.convention = convention; + } + + @Override + public T get() { + if (!this.isPresent()) { + throw new NullPointerException("Cannot get() from an empty Property. Set the value or set the convention."); + } else if (this.provider != null) { + return this.provider.get(); + } else { + return this.convention.get(); + } + } + +} diff --git a/src/main/java/groowt/util/fp/provider/LazyProvider.java b/src/main/java/groowt/util/fp/provider/LazyProvider.java new file mode 100644 index 0000000..2d0d34a --- /dev/null +++ b/src/main/java/groowt/util/fp/provider/LazyProvider.java @@ -0,0 +1,18 @@ +package groowt.util.fp.provider; + +import java.util.function.Supplier; + +final class LazyProvider implements Provider { + + private final Supplier lazy; + + public LazyProvider(Supplier supplier) { + this.lazy = supplier; + } + + @Override + public T get() { + return this.lazy.get(); + } + +} diff --git a/src/main/java/groowt/util/fp/provider/Provider.java b/src/main/java/groowt/util/fp/provider/Provider.java new file mode 100644 index 0000000..dc9ec3a --- /dev/null +++ b/src/main/java/groowt/util/fp/provider/Provider.java @@ -0,0 +1,26 @@ +package groowt.util.fp.provider; + +import java.util.function.Function; +import java.util.function.Supplier; + +public interface Provider { + + static Provider of(T t) { + return new SimpleProvider<>(t); + } + + static Provider ofLazy(Supplier tSupplier) { + return new LazyProvider<>(tSupplier); + } + + T get(); + + default Provider map(Function mapper) { + return new LazyProvider<>(() -> mapper.apply(this.get())); + } + + default Provider flatMap(Function> flatMapper) { + return new LazyProvider<>(() -> flatMapper.apply(this.get()).get()); + } + +} diff --git a/src/main/java/groowt/util/fp/provider/SimpleProvider.java b/src/main/java/groowt/util/fp/provider/SimpleProvider.java new file mode 100644 index 0000000..2220b1b --- /dev/null +++ b/src/main/java/groowt/util/fp/provider/SimpleProvider.java @@ -0,0 +1,18 @@ +package groowt.util.fp.provider; + +import java.util.Objects; + +final class SimpleProvider implements Provider { + + private final T t; + + public SimpleProvider(T t) { + this.t = Objects.requireNonNull(t); + } + + @Override + public T get() { + return t; + } + +}