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

com.jnape.palatable.lambda.monoid.builtin.EndoK Maven / Gradle / Ivy

There is a newer version: 5.5.0
Show newest version
package com.jnape.palatable.lambda.monoid.builtin;

import com.jnape.palatable.lambda.functions.Fn1;
import com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft;
import com.jnape.palatable.lambda.functions.specialized.MonoidFactory;
import com.jnape.palatable.lambda.functions.specialized.Pure;
import com.jnape.palatable.lambda.monad.MonadRec;
import com.jnape.palatable.lambda.monad.SafeT;
import com.jnape.palatable.lambda.monoid.Monoid;

import static com.jnape.palatable.lambda.functions.specialized.Kleisli.kleisli;
import static com.jnape.palatable.lambda.monad.SafeT.safeT;

/**
 * The monoid formed under monadic endomorphism.
 *
 * @param   the {@link MonadRec} witness
 * @param   the carrier type
 * @param  the fully witnessed {@link MonadRec} type
 */
public final class EndoK, A, MA extends MonadRec> implements
        MonoidFactory, Fn1> {

    private static final EndoK INSTANCE = new EndoK<>();

    @Override
    public Monoid> checkedApply(Pure pureM) {
        return new Monoid>() {
            @Override
            public Fn1 identity() {
                return pureM::apply;
            }

            @Override
            public Fn1 checkedApply(Fn1 f, Fn1 g) {
                return a -> kleisli(f).andThen(g::apply).apply(a);
            }

            @Override
            public  Fn1 foldMap(Fn1> fn, Iterable bs) {
                return a -> FoldLeft.foldLeft((f, b) -> f.fmap(ma -> ma.flatMap(a_ -> safeT(fn.apply(b).apply(a_)))),
                                              safeT(identity()).fmap(SafeT::safeT),
                                              bs)
                        .>>runSafeT()
                        .apply(a)
                        .runSafeT();
            }
        };
    }

    @SuppressWarnings("unchecked")
    public static , A, MA extends MonadRec> EndoK endoK() {
        return (EndoK) INSTANCE;
    }

    public static , A, MA extends MonadRec> Monoid> endoK(Pure pureM) {
        return EndoK.endoK().apply(pureM);
    }
}