README.org: expand TypeAlias documentation and add TypeAlias.flatMap()

This commit is contained in:
Paul Campbell 2018-07-16 20:56:56 +01:00
parent 78f15df464
commit e8989718f3
3 changed files with 195 additions and 5 deletions

View file

@ -119,6 +119,125 @@
} }
#+END_SRC #+END_SRC
*** =TypeAlias= *can* be a Monad
#+BEGIN_SRC java
package net.kemitix.mon;
import org.assertj.core.api.WithAssertions;
import org.junit.Test;
import java.util.function.Function;
public class TypeAliasMonadTest implements WithAssertions {
private final int v = 1;
private final Function<Integer, AnAlias<Integer>> f = i -> a(i * 2);
private final Function<Integer, AnAlias<Integer>> g = i -> a(i + 6);
private static AnAlias<Integer> a(Integer v) {
return AnAlias.of(v);
}
@Test
public void leftIdentity() {
assertThat(
a(v).flatMap(f)
).isEqualTo(
f.apply(v)
);
}
@Test
public void rightIdentity_inline() {
// java isn't able to properly infer the correct types when used in-line
assertThat(
a(v).<Integer, AnAlias<Integer>>flatMap(x -> a(x))
).isEqualTo(
a(v)
);
}
@Test
public void rightIdentity_explicitValue() {
final AnAlias<Integer> integerAnAlias = a(v).flatMap(x -> a(x));
assertThat(
integerAnAlias
).isEqualTo(
a(v)
);
}
@Test
public void associativity() {
assertThat(
a(v).flatMap(f).flatMap(g)
).isEqualTo(
a(v).flatMap(x -> f.apply(x).flatMap(g))
);
}
static class AnAlias<T> extends TypeAlias<T> {
private AnAlias(T value) {
super(value);
}
static <T> AnAlias<T> of(T value) {
return new AnAlias<>(value);
}
}
}
#+END_SRC
*** Instance Methods
**** =final <R> R map(final Function<T, R> f)=
Map the TypeAlias into another value.
#+BEGIN_SRC java
final StudentId studentId = StudentId.of(123);
final String idString = studentId.map(id -> String.valueOf(id));
class StudentId extends TypeAlias<Integer> {
private StudentId(Integer value) {
super(value);
}
static StudentId of(Integer id) {
return new StudentId(id);
}
}
#+END_SRC
**** =final <R, U extends TypeAlias<R>> U flatMap(final Function<T, U> f)=
Map the TypeAlias into another TypeAlias.
#+BEGIN_SRC java
final StudentId studentId = StudentId.of(123);
final StudentName studentName = studentId.flatMap(id -> getStudentName(id));
class StudentName extends TypeAlias<String> {
private StudentName(String value) {
super(value);
}
static StudentName of(final String name) {
return new StudentName(name);
}
}
#+END_SRC
**** =T getValue()=
Get the value of the TypeAlias.
#+BEGIN_SRC java
final String name = studentName.getValue();
#+END_SRC
** Maybe ** Maybe
@ -734,7 +853,7 @@
convention, used to indicate the error, and right the success. An alternative convention, used to indicate the error, and right the success. An alternative
is to use the =Result= which more clearly distinguishes success from failure. is to use the =Result= which more clearly distinguishes success from failure.
=Either= is not a Monad. *** =Either= *is not* a Monad.
*** Static Constructors *** Static Constructors
@ -746,6 +865,7 @@
final Either<Integer, String> left = Either.left(getIntegerValue()); final Either<Integer, String> left = Either.left(getIntegerValue());
#+END_SRC #+END_SRC
**** =static <L, R> Either<L, R> right(final R r)= **** =static <L, R> Either<L, R> right(final R r)=
Create a new Either holding a right value. Create a new Either holding a right value.
@ -766,6 +886,7 @@
final boolean rightIsLeft = Either.<Integer, String>right(getStringValue()).isLeft(); final boolean rightIsLeft = Either.<Integer, String>right(getStringValue()).isLeft();
#+END_SRC #+END_SRC
**** =boolean isRight()= **** =boolean isRight()=
Checks if the Either holds a right value. Checks if the Either holds a right value.
@ -788,6 +909,7 @@
); );
#+END_SRC #+END_SRC
**** =<T> Either<T, R> mapLeft(Function<L, T> f)= **** =<T> Either<T, R> mapLeft(Function<L, T> f)=
Map the function across the left value. Map the function across the left value.
@ -797,6 +919,7 @@
.mapLeft(i -> i.doubleValue()); .mapLeft(i -> i.doubleValue());
#+END_SRC #+END_SRC
**** =<T> Either<L, T> mapRight(Function<R, T> f)= **** =<T> Either<L, T> mapRight(Function<R, T> f)=
Map the function across the right value. Map the function across the right value.
@ -805,3 +928,5 @@
final Either<Integer, String> either = Either.<Integer, String>left(getIntegerValue()) final Either<Integer, String> either = Either.<Integer, String>left(getIntegerValue())
.mapRight(s -> s + "x"); .mapRight(s -> s + "x");
#+END_SRC #+END_SRC

View file

@ -30,7 +30,6 @@ import java.util.function.Function;
* for the type being aliased.</p> * for the type being aliased.</p>
* *
* @param <T> the type of the alias * @param <T> the type of the alias
*
* @author Paul Campbell (pcampbell@kemitix.net) * @author Paul Campbell (pcampbell@kemitix.net)
*/ */
@SuppressWarnings("abstractclassname") @SuppressWarnings("abstractclassname")
@ -55,13 +54,24 @@ public abstract class TypeAlias<T> {
* *
* @param f the function to create the new value * @param f the function to create the new value
* @param <R> the type of the new value * @param <R> the type of the new value
* * @return the result of the function
* @return a TypeAlias
*/ */
public final <R> R map(final Function<T, R> f) { public final <R> R map(final Function<T, R> f) {
return f.apply(value); return f.apply(value);
} }
/**
* Map the TypeAlias into another TypeAlias.
*
* @param f the function to create the new value
* @param <R> the type of the new value within a TypeAlias
* @param <U> the type of the TypeAlias superclass containing the new value
* @return a TypeAlias
*/
public final <R, U extends TypeAlias<R>> U flatMap(final Function<T, U> f) {
return f.apply(value);
}
@Override @Override
public final int hashCode() { public final int hashCode() {
return value.hashCode(); return value.hashCode();
@ -73,7 +83,7 @@ public abstract class TypeAlias<T> {
final TypeAlias other = (TypeAlias) o; final TypeAlias other = (TypeAlias) o;
final Class<?> otherValueClass = other.value.getClass(); final Class<?> otherValueClass = other.value.getClass();
return otherValueClass.equals(getValue().getClass()) return otherValueClass.equals(getValue().getClass())
&& other.value.equals(getValue()); && other.value.equals(getValue());
} }
return map(o::equals); return map(o::equals);
} }

View file

@ -0,0 +1,55 @@
package net.kemitix.mon;
import org.assertj.core.api.WithAssertions;
import org.junit.Test;
import java.util.function.Function;
public class TypeAliasMonadTest implements WithAssertions {
private final int v = 1;
private final Function<Integer, AnAlias<Integer>> f = i -> a(i * 2);
private final Function<Integer, AnAlias<Integer>> g = i -> a(i + 6);
private static AnAlias<Integer> a(Integer v) {
return AnAlias.of(v);
}
@Test
public void leftIdentity() {
assertThat(
a(v).flatMap(f)
).isEqualTo(
f.apply(v)
);
}
@Test
public void rightIdentity() {
final AnAlias<Integer> integerAnAlias = a(v).flatMap(x -> a(x));
assertThat(
integerAnAlias
).isEqualTo(
a(v)
);
}
@Test
public void associativity() {
assertThat(
a(v).flatMap(f).flatMap(g)
).isEqualTo(
a(v).flatMap(x -> f.apply(x).flatMap(g))
);
}
static class AnAlias<T> extends TypeAlias<T> {
private AnAlias(T value) {
super(value);
}
static <T> AnAlias<T> of(T value) {
return new AnAlias<>(value);
}
}
}