From 9f1881fb08245d43924e792c6c676b57ac247ad0 Mon Sep 17 00:00:00 2001 From: Thibaud Date: Mon, 27 Jan 2020 21:51:35 +0100 Subject: [PATCH] lang: add some monads examples --- lang/src/main/java/monads/Monad.java | 13 ++++ .../main/java/monads/OptionalExamples.java | 69 +++++++++++++++++++ lang/src/main/java/monads/ResultExamples.java | 37 ++++++++++ lang/src/main/java/monads/StreamExamples.java | 33 +++++++++ .../main/java/monads/util/OptionalUtils.java | 23 +++++++ 5 files changed, 175 insertions(+) create mode 100644 lang/src/main/java/monads/Monad.java create mode 100644 lang/src/main/java/monads/OptionalExamples.java create mode 100644 lang/src/main/java/monads/ResultExamples.java create mode 100644 lang/src/main/java/monads/StreamExamples.java create mode 100644 lang/src/main/java/monads/util/OptionalUtils.java diff --git a/lang/src/main/java/monads/Monad.java b/lang/src/main/java/monads/Monad.java new file mode 100644 index 0000000..804e5d5 --- /dev/null +++ b/lang/src/main/java/monads/Monad.java @@ -0,0 +1,13 @@ +package monads; + +import java.util.function.Function; + +public interface Monad { + static Monad unit(U value) { + return null; + } + Monad flatMap(Function> mapper); + default Monad map(Function mapper) { + return flatMap(t -> unit(mapper.apply(t))); + } +} diff --git a/lang/src/main/java/monads/OptionalExamples.java b/lang/src/main/java/monads/OptionalExamples.java new file mode 100644 index 0000000..d02257e --- /dev/null +++ b/lang/src/main/java/monads/OptionalExamples.java @@ -0,0 +1,69 @@ +package monads; + +import java.util.Optional; + +import static monads.util.OptionalUtils.optionalAdd; + +public class OptionalExamples { + + private final Soundcard soundcard; + private final Computer computer; + private final USB usb; + + public OptionalExamples() { + usb = new USB("3.1"); + soundcard = new Soundcard(usb); + computer = new Computer(soundcard); + } + + private void nestedOptional() { + System.out.println("Nested optionals example"); + var version = computer.getSoundcard() + .flatMap(Soundcard::getUSB) + .map(USB::getVersion) + .orElse("UNKNOWN"); + System.out.printf("Version : %s%n", version); + } + + private void addOptionals() { + System.out.println("Add optionals example"); + assert optionalAdd(Optional.of(1), Optional.of(1)).equals(Optional.of(2)); + assert optionalAdd(Optional.of(1), Optional.of(1)).equals(Optional.empty()); + } + + public static void main(String[] args) { + var examples = new OptionalExamples(); + examples.nestedOptional(); + examples.addOptionals(); + } + + private static class Computer { + private final Soundcard soundcard; + + private Computer(Soundcard soundcard) { + this.soundcard = soundcard; + } + + public Optional getSoundcard() { return Optional.ofNullable(soundcard); } + } + + private static class Soundcard { + private final USB usb; + + private Soundcard(USB usb) { + this.usb = usb; + } + + public Optional getUSB() { return Optional.ofNullable(usb); } + } + + private static class USB { + private final String version; + + private USB(String version) { + this.version = version; + } + + public String getVersion(){ return version; } + } +} diff --git a/lang/src/main/java/monads/ResultExamples.java b/lang/src/main/java/monads/ResultExamples.java new file mode 100644 index 0000000..59f2a45 --- /dev/null +++ b/lang/src/main/java/monads/ResultExamples.java @@ -0,0 +1,37 @@ +package monads; + +public class ResultExamples { + public static void main(String[] args) { +// var ok = Result.ok(); + } + + private static class Result { + private final T value; + private final String error; + + private Result(T value, String error) { + this.value = value; + this.error = error; + } + + public static Result ok(U value) { + return new Result<>(value, null); + } + + public static Result error(String error) { + return new Result<>(null, error); + } + + public boolean isError() { + return error != null; + } + + public String getError() { + return error; + } + + public T getValue() { + return value; + } + } +} diff --git a/lang/src/main/java/monads/StreamExamples.java b/lang/src/main/java/monads/StreamExamples.java new file mode 100644 index 0000000..4315556 --- /dev/null +++ b/lang/src/main/java/monads/StreamExamples.java @@ -0,0 +1,33 @@ +package monads; + +import java.util.stream.Stream; + +public class StreamExamples { + /** + * Given n > 0 find all pairs (i; j) where + * 1 < j <= i <= n and i + j is prime + */ + private Stream findPrimes(long n) { + return Stream.iterate(1, i -> i + 1) + .limit(n) + .flatMap(i -> Stream.iterate(1, j -> j + 1) + .limit(n) + .map(j -> new long[] {i, j}) + ).filter(pair -> isPrime(pair[0] + pair[1])); + } + + private boolean isPrime(long n) { + return Stream.iterate(2, i -> i + 1) + .limit((long) Math.sqrt(n)) + .noneMatch(i -> n % i == 0); + } + + public static void main(String[] args) { + StreamExamples examples = new StreamExamples(); + var start = System.nanoTime(); + var primes = (Long) examples.findPrimes(10L).count(); + var end = System.nanoTime(); + System.out.printf("Elapsed : %fs", (end - start) / 1_000_000_000.0); + //primes.map(Arrays::toString).forEach(System.out::println); + } +} diff --git a/lang/src/main/java/monads/util/OptionalUtils.java b/lang/src/main/java/monads/util/OptionalUtils.java new file mode 100644 index 0000000..71d5ac1 --- /dev/null +++ b/lang/src/main/java/monads/util/OptionalUtils.java @@ -0,0 +1,23 @@ +package monads.util; + +import java.util.Optional; +import java.util.function.BiFunction; + +public final class OptionalUtils { + @SuppressWarnings("OptionalUsedAsFieldOrParameterType") + public static Optional optionalAdd(Optional val1, Optional val2) { + return flatMap2(val1, val2, (first, second) -> Optional.of(first + second)); + } + + @SuppressWarnings("OptionalUsedAsFieldOrParameterType") + public static Optional flatMap2( + Optional opt1, + Optional opt2, + BiFunction> mapper + ) { + return opt1.flatMap(a -> + opt2.flatMap(b -> + mapper.apply(a, b) + )); + } +}