README.org: expand TypeAlias documentation and add TypeAlias.flatMap()
This commit is contained in:
parent
78f15df464
commit
e8989718f3
3 changed files with 195 additions and 5 deletions
127
README.org
127
README.org
|
@ -119,6 +119,125 @@
|
|||
}
|
||||
#+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
|
||||
|
||||
|
@ -734,7 +853,7 @@
|
|||
convention, used to indicate the error, and right the success. An alternative
|
||||
is to use the =Result= which more clearly distinguishes success from failure.
|
||||
|
||||
=Either= is not a Monad.
|
||||
*** =Either= *is not* a Monad.
|
||||
|
||||
*** Static Constructors
|
||||
|
||||
|
@ -746,6 +865,7 @@
|
|||
final Either<Integer, String> left = Either.left(getIntegerValue());
|
||||
#+END_SRC
|
||||
|
||||
|
||||
**** =static <L, R> Either<L, R> right(final R r)=
|
||||
|
||||
Create a new Either holding a right value.
|
||||
|
@ -766,6 +886,7 @@
|
|||
final boolean rightIsLeft = Either.<Integer, String>right(getStringValue()).isLeft();
|
||||
#+END_SRC
|
||||
|
||||
|
||||
**** =boolean isRight()=
|
||||
|
||||
Checks if the Either holds a right value.
|
||||
|
@ -788,6 +909,7 @@
|
|||
);
|
||||
#+END_SRC
|
||||
|
||||
|
||||
**** =<T> Either<T, R> mapLeft(Function<L, T> f)=
|
||||
|
||||
Map the function across the left value.
|
||||
|
@ -797,6 +919,7 @@
|
|||
.mapLeft(i -> i.doubleValue());
|
||||
#+END_SRC
|
||||
|
||||
|
||||
**** =<T> Either<L, T> mapRight(Function<R, T> f)=
|
||||
|
||||
Map the function across the right value.
|
||||
|
@ -805,3 +928,5 @@
|
|||
final Either<Integer, String> either = Either.<Integer, String>left(getIntegerValue())
|
||||
.mapRight(s -> s + "x");
|
||||
#+END_SRC
|
||||
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@ import java.util.function.Function;
|
|||
* for the type being aliased.</p>
|
||||
*
|
||||
* @param <T> the type of the alias
|
||||
*
|
||||
* @author Paul Campbell (pcampbell@kemitix.net)
|
||||
*/
|
||||
@SuppressWarnings("abstractclassname")
|
||||
|
@ -55,13 +54,24 @@ public abstract class TypeAlias<T> {
|
|||
*
|
||||
* @param f the function to create the new value
|
||||
* @param <R> the type of the new value
|
||||
*
|
||||
* @return a TypeAlias
|
||||
* @return the result of the function
|
||||
*/
|
||||
public final <R> R map(final Function<T, R> f) {
|
||||
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
|
||||
public final int hashCode() {
|
||||
return value.hashCode();
|
||||
|
@ -73,7 +83,7 @@ public abstract class TypeAlias<T> {
|
|||
final TypeAlias other = (TypeAlias) o;
|
||||
final Class<?> otherValueClass = other.value.getClass();
|
||||
return otherValueClass.equals(getValue().getClass())
|
||||
&& other.value.equals(getValue());
|
||||
&& other.value.equals(getValue());
|
||||
}
|
||||
return map(o::equals);
|
||||
}
|
||||
|
|
55
src/test/java/net/kemitix/mon/TypeAliasMonadTest.java
Normal file
55
src/test/java/net/kemitix/mon/TypeAliasMonadTest.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue