Maybe satisfies the three Monad Laws
This commit is contained in:
parent
2211182c7d
commit
5d39be36ff
6 changed files with 103 additions and 0 deletions
|
@ -55,6 +55,8 @@ class Example {
|
||||||
|
|
||||||
### Maybe
|
### Maybe
|
||||||
|
|
||||||
|
A Monad.
|
||||||
|
|
||||||
A non-final substitute for Optional with `peek()` and `stream()` methods.
|
A non-final substitute for Optional with `peek()` and `stream()` methods.
|
||||||
|
|
||||||
```java
|
```java
|
||||||
|
|
|
@ -43,6 +43,11 @@ final class Just<T> implements Maybe<T> {
|
||||||
|
|
||||||
private final T value;
|
private final T value;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <R> Maybe<R> flatMap(Function<T, Maybe<R>> f) {
|
||||||
|
return f.apply(value);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <R> Maybe<R> map(final Function<T, R> f) {
|
public <R> Maybe<R> map(final Function<T, R> f) {
|
||||||
return new Just<>(f.apply(value));
|
return new Just<>(f.apply(value));
|
||||||
|
|
|
@ -76,6 +76,15 @@ public interface Maybe<T> extends Functor<T, Maybe<?>> {
|
||||||
return new Just<>(value);
|
return new Just<>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Monad binder maps the Maybe into another Maybe using the binder method f.
|
||||||
|
*
|
||||||
|
* @param f the mapper function
|
||||||
|
* @param <R> the type of the value in the final maybe
|
||||||
|
* @return a Maybe with the mapped value
|
||||||
|
*/
|
||||||
|
<R> Maybe<R> flatMap(Function<T, Maybe<R>> f);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
<R> Maybe<R> map(Function<T, R> f);
|
<R> Maybe<R> map(Function<T, R> f);
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,11 @@ final class Nothing<T> implements Maybe<T> {
|
||||||
|
|
||||||
static final Maybe<?> INSTANCE = new Nothing<>();
|
static final Maybe<?> INSTANCE = new Nothing<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <R> Maybe<R> flatMap(Function<T, Maybe<R>> f) {
|
||||||
|
return Maybe.nothing();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <R> Maybe<R> map(final Function<T, R> f) {
|
public <R> Maybe<R> map(final Function<T, R> f) {
|
||||||
|
|
39
src/test/java/net/kemitix/mon/MaybeMonadTest.java
Normal file
39
src/test/java/net/kemitix/mon/MaybeMonadTest.java
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
package net.kemitix.mon;
|
||||||
|
|
||||||
|
import net.kemitix.mon.maybe.Maybe;
|
||||||
|
import org.assertj.core.api.WithAssertions;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class MaybeMonadTest implements WithAssertions {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void leftIdentity() {
|
||||||
|
//given
|
||||||
|
final int value = 1;
|
||||||
|
final Maybe<Integer> maybe = Maybe.maybe(value);
|
||||||
|
final Function<Integer, Maybe<Integer>> f = i -> Maybe.maybe(i * 2);
|
||||||
|
//then
|
||||||
|
assertThat(maybe.flatMap(f)).isEqualTo(f.apply(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void rightIdentity() {
|
||||||
|
//given
|
||||||
|
final Maybe<Integer> maybe = Maybe.maybe(1);
|
||||||
|
//then
|
||||||
|
assertThat(maybe.flatMap(Maybe::maybe)).isEqualTo(maybe);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void associativity() {
|
||||||
|
//given
|
||||||
|
final Maybe<Integer> maybe = Maybe.maybe(1);
|
||||||
|
final Function<Integer, Maybe<Integer>> f = i -> Maybe.maybe(i * 2);
|
||||||
|
final Function<Integer, Maybe<Integer>> g = i -> Maybe.maybe(i + 6);
|
||||||
|
//then
|
||||||
|
assertThat(maybe.flatMap(f).flatMap(g)).isEqualTo(maybe.flatMap(x -> f.apply(x).flatMap(g)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -123,4 +123,47 @@ public class MaybeTest implements WithAssertions {
|
||||||
//then
|
//then
|
||||||
assertThat(stream).isEmpty();
|
assertThat(stream).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void justFlatMap() {
|
||||||
|
//given
|
||||||
|
final Maybe<Integer> just1 = Maybe.just(1);
|
||||||
|
final Maybe<Integer> just2 = Maybe.just(2);
|
||||||
|
//when
|
||||||
|
final Maybe<Integer> result = just1.flatMap(v1 ->
|
||||||
|
just2.flatMap(v2 ->
|
||||||
|
Maybe.maybe(v1 + v2)
|
||||||
|
));
|
||||||
|
//then
|
||||||
|
assertThat(result.toOptional()).contains(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nothingFlatMap() {
|
||||||
|
//given
|
||||||
|
final Maybe<Integer> nothing1 = Maybe.nothing();
|
||||||
|
final Maybe<Integer> nothing2 = Maybe.nothing();
|
||||||
|
//when
|
||||||
|
final Maybe<Integer> result = nothing1.flatMap(v1 ->
|
||||||
|
nothing2.flatMap(v2 ->
|
||||||
|
Maybe.maybe(v1 + v2)
|
||||||
|
));
|
||||||
|
//then
|
||||||
|
assertThat(result.toOptional()).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void justNothingFlatMap() {
|
||||||
|
//given
|
||||||
|
final Maybe<Integer> just1 = Maybe.just(1);
|
||||||
|
final Maybe<Integer> nothing2 = Maybe.nothing();
|
||||||
|
//when
|
||||||
|
final Maybe<Integer> result = just1.flatMap(v1 ->
|
||||||
|
nothing2.flatMap(v2 ->
|
||||||
|
Maybe.maybe(v1 + v2)
|
||||||
|
));
|
||||||
|
//then
|
||||||
|
assertThat(result.toOptional()).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue