Maybe satisfies the three Monad Laws

This commit is contained in:
Paul Campbell 2018-06-25 22:35:31 +01:00
parent 2211182c7d
commit 5d39be36ff
6 changed files with 103 additions and 0 deletions

View file

@ -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

View file

@ -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));

View file

@ -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);

View file

@ -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) {

View 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)));
}
}

View file

@ -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();
}
} }