// Path: a-foundation/src/main/java/com/ajjpj/afoundation/function/AFunction1.java
// public interface AFunction1<P, R, E extends Throwable> extends Serializable {
//     R apply(P param) throws E;
// }
// 
// Path: a-foundation/src/main/java/com/ajjpj/afoundation/function/APartialFunction.java
// public interface APartialFunction<P, R, E extends Throwable> extends AFunction1<P, R, E> {
//     boolean isDefinedAt (P param);
// }
// 
// Path: a-foundation/src/main/java/com/ajjpj/afoundation/function/APredicate.java
// public interface APredicate<T,E extends Throwable> extends Serializable {
//     boolean apply(T o) throws E;
// }


import com.ajjpj.afoundation.function.AFunction1;
import com.ajjpj.afoundation.function.APartialFunction;
import com.ajjpj.afoundation.function.APredicate;
package com.ajjpj.afoundation.collection.immutable;


/**
 * This interface contains those functional operations that are supported for all kinds of collections. This is the greatest common
 *  denominator of all a-base collection classes.
 *
 * @author arno
 */
public interface AMonadicOps<T> {
    /**
     * Filters this collection's elements, this method returns a new collection comprised of only those elements that match
     *  a given predicate.
     */
    <E extends Throwable> AMonadicOps<T> filter (APredicate<? super T, E> pred) throws E;

    /**
     * Filters this collection's elements, this method returns a new collection comprised of only those elements that do not match
     *  a given predicate.
     */
    <E extends Throwable> AMonadicOps<T> filterNot (APredicate<? super T, E> pred) throws E;

    /**
     * Turns a collection of collections into a 'flat' collection, removing one layer of collections.
     */
    <X> AMonadicOps<X> flatten();

    /**
     * Applies a transformation function to each element, creating a new collection instance from the results. For a
     *  collection of strings, this could e.g. be used to create a collection of integer values with each string's length.
     */
    <X,E extends Throwable> AMonadicOps<X> map(AFunction1<? super T, ? extends X, E> f) throws E;

    /**
     * Maps each element to a collection of values, flattening the results into a single collection. Let there be a
     *  collection of strings. Calling <code>flatMap</code> with a function that splits a string into tokens, the result
     *  would be a collection of all tokens of all original strings.
     */
    <X, E extends Throwable> AMonadicOps<X> flatMap(AFunction1<? super T, ? extends Iterable<X>, E> f) throws E;

    /**
     * Applies a transformation function to all elements of a collection, where the partial function is defined for. Creates a new collection
     *   of the transformed elements only. So the number of result elements may be less than the number of elements in the source collection.
     */
// Path: a-foundation/src/main/java/com/ajjpj/afoundation/function/AFunction1.java
// public interface AFunction1<P, R, E extends Throwable> extends Serializable {
//     R apply(P param) throws E;
// }
// 
// Path: a-foundation/src/main/java/com/ajjpj/afoundation/function/APartialFunction.java
// public interface APartialFunction<P, R, E extends Throwable> extends AFunction1<P, R, E> {
//     boolean isDefinedAt (P param);
// }
// 
// Path: a-foundation/src/main/java/com/ajjpj/afoundation/function/APredicate.java
// public interface APredicate<T,E extends Throwable> extends Serializable {
//     boolean apply(T o) throws E;
// }


// Path: a-foundation/src/main/java/com/ajjpj/afoundation/collection/immutable/AMonadicOps.java
import com.ajjpj.afoundation.function.AFunction1;
import com.ajjpj.afoundation.function.APartialFunction;
import com.ajjpj.afoundation.function.APredicate;

package com.ajjpj.afoundation.collection.immutable;


/**
 * This interface contains those functional operations that are supported for all kinds of collections. This is the greatest common
 *  denominator of all a-base collection classes.
 *
 * @author arno
 */
public interface AMonadicOps<T> {
    /**
     * Filters this collection's elements, this method returns a new collection comprised of only those elements that match
     *  a given predicate.
     */
    <E extends Throwable> AMonadicOps<T> filter (APredicate<? super T, E> pred) throws E;

    /**
     * Filters this collection's elements, this method returns a new collection comprised of only those elements that do not match
     *  a given predicate.
     */
    <E extends Throwable> AMonadicOps<T> filterNot (APredicate<? super T, E> pred) throws E;

    /**
     * Turns a collection of collections into a 'flat' collection, removing one layer of collections.
     */
    <X> AMonadicOps<X> flatten();

    /**
     * Applies a transformation function to each element, creating a new collection instance from the results. For a
     *  collection of strings, this could e.g. be used to create a collection of integer values with each string's length.
     */
    <X,E extends Throwable> AMonadicOps<X> map(AFunction1<? super T, ? extends X, E> f) throws E;

    /**
     * Maps each element to a collection of values, flattening the results into a single collection. Let there be a
     *  collection of strings. Calling <code>flatMap</code> with a function that splits a string into tokens, the result
     *  would be a collection of all tokens of all original strings.
     */
    <X, E extends Throwable> AMonadicOps<X> flatMap(AFunction1<? super T, ? extends Iterable<X>, E> f) throws E;

    /**
     * Applies a transformation function to all elements of a collection, where the partial function is defined for. Creates a new collection
     *   of the transformed elements only. So the number of result elements may be less than the number of elements in the source collection.
     */
    <X, E extends Throwable> AMonadicOps<X> collect (APartialFunction<? super T, ? extends X, E> pf) throws E;