All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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 *

* 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> mapper); @Override Monad map(Function 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, U>> f) { return Monad.of(list.flatMap((T t) -> (List) f.apply(t).narrow())); } @Override public Monad, U> map(Function 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 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 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 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 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 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 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 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 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 { > Monad apply(Monad m1, Monad m2, Monad m3, Monad m4, Monad m5, Monad m6, Monad m7); } /** * Represents a function {@code (T1, T2, T3, T4, T5, T6, T7, T8) -> R} * lifted to {@code (M, 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 8th argument type * @param result type */ // DEV-NOTE: intentionally not a @FunctionalInterface interface Lifted8 { > Monad apply(Monad m1, Monad m2, Monad m3, Monad m4, Monad m5, Monad m6, Monad m7, Monad m8); } }