javaslang.algebra.Monad Maven / Gradle / Ivy
/* / \____ _ _ ____ ______ / \ ____ __ _______
* / / \/ \ / \/ \ / /\__\/ // \/ \ // /\__\ JΛVΛSLΛNG
* _/ / /\ \ \/ / /\ \\__\\ \ // /\ \ /\\/ \ /__\ \ Copyright 2014-2017 Javaslang, http://javaslang.io
* /___/\_/ \_/\____/\_/ \_/\__\/__/\__\_/ \_// \__/\_____/ Licensed under the Apache License, Version 2.0
*/
package javaslang.algebra;
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*\
G E N E R A T O R C R A F T E D
\*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
import java.util.function.BiFunction;
import java.util.function.Function;
import javaslang.*;
import javaslang.collection.List;
/**
* Defines a Monad by generalizing the flatMap function.
*
* A {@code Monad} is a {@link Functor} with a {@code flatMap} method that satisfies the Monad laws, also known
* as the three control laws:
*
* Let
*
* - {@code A}, {@code B}, {@code C} be types
* - {@code unit: A -> Monad} a constructor
* - {@code f: A -> Monad}, {@code g: B -> Monad
} functions
* - {@code a} be an object of type {@code A}
* - {@code m} be an object of type {@code Monad}
*
* Then all instances of the {@code Monad} interface should obey the three control laws:
*
* - Left identity: {@code unit(a).flatMap(f) ≡ f a}
* - Right identity: {@code m.flatMap(unit) ≡ m}
* - Associativity: {@code m.flatMap(f).flatMap(g) ≡ m.flatMap(x -> f.apply(x).flatMap(g))}
*
*
* To read further about monads in Java please refer to
* What's Wrong in Java 8, Part IV: Monads.
*
* @param Type M<?> of a monadic instance, which is covered by this Monad
* @param component type of this monad
* @author Daniel Dietrich
* @since 1.1.0
*/
public interface Monad, T> extends Functor {
/**
* FlatMaps this Monad to a new Monad with different component type.
*
* FlatMap is the sequence operation for functions and behaves like the imperative {@code ;}.
*
* If the previous results are needed, flatMap cascades:
*
*
* m1().flatMap(result1 ->
* m2(result1).flatMap(result2 ->
* m3(result1, result2).flatMap(result3 ->
* ...
* )
* )
* );
*
*
* If only the last result is needed, flatMap may be used sequentially:
*
*
* m1().flatMap(this::m2)
* .flatMap(this::m3)
* .flatMap(...);
*
*
*
* @param mapper A mapper
* @param Component type of the mapped {@code Monad}
* @return a mapped {@code Monad}
* @throws NullPointerException if {@code mapper} is null
*/
Monad flatMap(Function super T, ? extends Monad> mapper);
@Override
Monad map(Function super T, ? extends U> mapper);
/**
* Pulls the monadic instance of type M<?> out of this Monad view.
* This instance can be safely casted to type M<T>.
*
* @return the monadic instance wrapped by this Monad
*/
Kind1 narrow();
// static factory methods
static Monad, T> of(List list) {
return new Monad, T>() {
@Override
public Monad, U> flatMap(Function super T, ? extends Monad, U>> f) {
return Monad.of(list.flatMap((T t) -> (List) f.apply(t).narrow()));
}
@Override
public Monad, U> map(Function super T, ? extends U> f) {
return Monad.of(list.map(f));
}
@Override
public List narrow() {
return list;
}
};
}
// lifting functions
/**
* Lifts a {@code Function} to a higher {@code Lifted1} function that operates on Monads.
*
* @param 1st argument type of f
* @param result type of f
* @param f a Function
* @return a new Lifted1 function that lifts the given function f in a layer that operates on monads.
*/
static Lifted1 lift(Function super T, ? extends R> f) {
return new Lifted1() {
@Override
public > Monad apply(Monad m) {
return m.map(f);
}
};
}
/**
* Lifts a {@code BiFunction} to a higher {@code Lifted2} function that operates on Monads.
*
* @param 1st argument type of f
* @param 2nd argument type of f
* @param result type of f
* @param f a BiFunction
* @return a new Lifted2 function that lifts the given function f in a layer that operates on monads.
*/
static Lifted2 lift(BiFunction super T1, ? super T2, ? extends R> f) {
return new Lifted2() {
@Override
public > Monad apply(Monad m1, Monad m2) {
return
m1.flatMap(t1 ->
m2.map(t2 -> f.apply(t1, t2)));
}
};
}
/**
* Lifts a {@code Function3} to a higher {@code Lifted3} function that operates on Monads.
*
* @param 1st argument type of f
* @param 2nd argument type of f
* @param 3rd argument type of f
* @param result type of f
* @param f a Function3
* @return a new Lifted3 function that lifts the given function f in a layer that operates on monads.
*/
static Lifted3 lift(Function3 super T1, ? super T2, ? super T3, ? extends R> f) {
return new Lifted3() {
@Override
public > Monad apply(Monad m1, Monad m2, Monad m3) {
return
m1.flatMap(t1 ->
m2.flatMap(t2 ->
m3.map(t3 -> f.apply(t1, t2, t3))));
}
};
}
/**
* Lifts a {@code Function4} to a higher {@code Lifted4} function that operates on Monads.
*
* @param 1st argument type of f
* @param 2nd argument type of f
* @param 3rd argument type of f
* @param 4th argument type of f
* @param result type of f
* @param f a Function4
* @return a new Lifted4 function that lifts the given function f in a layer that operates on monads.
*/
static Lifted4 lift(Function4 super T1, ? super T2, ? super T3, ? super T4, ? extends R> f) {
return new Lifted4() {
@Override
public > Monad apply(Monad m1, Monad m2, Monad m3, Monad m4) {
return
m1.flatMap(t1 ->
m2.flatMap(t2 ->
m3.flatMap(t3 ->
m4.map(t4 -> f.apply(t1, t2, t3, t4)))));
}
};
}
/**
* Lifts a {@code Function5} to a higher {@code Lifted5} function that operates on Monads.
*
* @param 1st argument type of f
* @param 2nd argument type of f
* @param 3rd argument type of f
* @param 4th argument type of f
* @param 5th argument type of f
* @param result type of f
* @param f a Function5
* @return a new Lifted5 function that lifts the given function f in a layer that operates on monads.
*/
static Lifted5 lift(Function5 super T1, ? super T2, ? super T3, ? super T4, ? super T5, ? extends R> f) {
return new Lifted5() {
@Override
public > Monad apply(Monad m1, Monad m2, Monad m3, Monad m4, Monad m5) {
return
m1.flatMap(t1 ->
m2.flatMap(t2 ->
m3.flatMap(t3 ->
m4.flatMap(t4 ->
m5.map(t5 -> f.apply(t1, t2, t3, t4, t5))))));
}
};
}
/**
* Lifts a {@code Function6} to a higher {@code Lifted6} function that operates on Monads.
*
* @param 1st argument type of f
* @param 2nd argument type of f
* @param 3rd argument type of f
* @param 4th argument type of f
* @param 5th argument type of f
* @param 6th argument type of f
* @param result type of f
* @param f a Function6
* @return a new Lifted6 function that lifts the given function f in a layer that operates on monads.
*/
static Lifted6 lift(Function6 super T1, ? super T2, ? super T3, ? super T4, ? super T5, ? super T6, ? extends R> f) {
return new Lifted6() {
@Override
public > Monad apply(Monad m1, Monad m2, Monad m3, Monad m4, Monad m5, Monad m6) {
return
m1.flatMap(t1 ->
m2.flatMap(t2 ->
m3.flatMap(t3 ->
m4.flatMap(t4 ->
m5.flatMap(t5 ->
m6.map(t6 -> f.apply(t1, t2, t3, t4, t5, t6)))))));
}
};
}
/**
* Lifts a {@code Function7} to a higher {@code Lifted7} function that operates on Monads.
*
* @param 1st argument type of f
* @param 2nd argument type of f
* @param 3rd argument type of f
* @param 4th argument type of f
* @param 5th argument type of f
* @param 6th argument type of f
* @param 7th argument type of f
* @param result type of f
* @param f a Function7
* @return a new Lifted7 function that lifts the given function f in a layer that operates on monads.
*/
static Lifted7 lift(Function7 super T1, ? super T2, ? super T3, ? super T4, ? super T5, ? super T6, ? super T7, ? extends R> f) {
return new Lifted7() {
@Override
public > Monad apply(Monad m1, Monad m2, Monad m3, Monad m4, Monad m5, Monad m6, Monad m7) {
return
m1.flatMap(t1 ->
m2.flatMap(t2 ->
m3.flatMap(t3 ->
m4.flatMap(t4 ->
m5.flatMap(t5 ->
m6.flatMap(t6 ->
m7.map(t7 -> f.apply(t1, t2, t3, t4, t5, t6, t7))))))));
}
};
}
/**
* Lifts a {@code Function8} to a higher {@code Lifted8} function that operates on Monads.
*
* @param 1st argument type of f
* @param 2nd argument type of f
* @param 3rd argument type of f
* @param 4th argument type of f
* @param 5th argument type of f
* @param 6th argument type of f
* @param 7th argument type of f
* @param 8th argument type of f
* @param result type of f
* @param f a Function8
* @return a new Lifted8 function that lifts the given function f in a layer that operates on monads.
*/
static Lifted8 lift(Function8 super T1, ? super T2, ? super T3, ? super T4, ? super T5, ? super T6, ? super T7, ? super T8, ? extends R> f) {
return new Lifted8() {
@Override
public > Monad apply(Monad m1, Monad m2, Monad m3, Monad m4, Monad m5, Monad m6, Monad m7, Monad m8) {
return
m1.flatMap(t1 ->
m2.flatMap(t2 ->
m3.flatMap(t3 ->
m4.flatMap(t4 ->
m5.flatMap(t5 ->
m6.flatMap(t6 ->
m7.flatMap(t7 ->
m8.map(t8 -> f.apply(t1, t2, t3, t4, t5, t6, t7, t8)))))))));
}
};
}
// -- lifted types
/**
* Represents a function {@code T -> R}
* lifted to {@code M -> M}.
*
* @param 1st argument type
* @param result type
*/
// DEV-NOTE: intentionally not a @FunctionalInterface
interface Lifted1 {
> Monad apply(Monad m);
}
/**
* Represents a function {@code (T1, T2) -> R}
* lifted to {@code (M, M) -> M}.
*
* @param 1st argument type
* @param 2nd argument type
* @param result type
*/
// DEV-NOTE: intentionally not a @FunctionalInterface
interface Lifted2 {
> Monad apply(Monad m1, Monad m2);
}
/**
* Represents a function {@code (T1, T2, T3) -> R}
* lifted to {@code (M, M, M) -> M}.
*
* @param 1st argument type
* @param 2nd argument type
* @param 3rd argument type
* @param result type
*/
// DEV-NOTE: intentionally not a @FunctionalInterface
interface Lifted3 {
> Monad apply(Monad m1, Monad m2, Monad m3);
}
/**
* Represents a function {@code (T1, T2, T3, T4) -> R}
* lifted to {@code (M, M, M, M) -> M}.
*
* @param 1st argument type
* @param 2nd argument type
* @param 3rd argument type
* @param 4th argument type
* @param result type
*/
// DEV-NOTE: intentionally not a @FunctionalInterface
interface Lifted4 {
> Monad apply(Monad m1, Monad m2, Monad m3, Monad m4);
}
/**
* Represents a function {@code (T1, T2, T3, T4, T5) -> R}
* lifted to {@code (M, M, M, M, M) -> M}.
*
* @param 1st argument type
* @param 2nd argument type
* @param 3rd argument type
* @param 4th argument type
* @param 5th argument type
* @param result type
*/
// DEV-NOTE: intentionally not a @FunctionalInterface
interface Lifted5 {
> Monad apply(Monad m1, Monad m2, Monad m3, Monad m4, Monad m5);
}
/**
* Represents a function {@code (T1, T2, T3, T4, T5, T6) -> R}
* lifted to {@code (M, M, M, M, M, M) -> M}.
*
* @param 1st argument type
* @param 2nd argument type
* @param 3rd argument type
* @param 4th argument type
* @param 5th argument type
* @param 6th argument type
* @param result type
*/
// DEV-NOTE: intentionally not a @FunctionalInterface
interface Lifted6 {
> Monad apply(Monad m1, Monad m2, Monad m3, Monad m4, Monad m5, Monad m6);
}
/**
* Represents a function {@code (T1, T2, T3, T4, T5, T6, T7) -> R}
* lifted to {@code (M, M, M, M, M, M, M) -> M}.
*
* @param 1st argument type
* @param 2nd argument type
* @param 3rd argument type
* @param 4th argument type
* @param 5th argument type
* @param 6th argument type
* @param 7th argument type
* @param result type
*/
// DEV-NOTE: intentionally not a @FunctionalInterface
interface Lifted7