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