![JAR search and dependency download from the Maven repository](/logo.png)
com.github.tonivade.purefun.free.FreeAp Maven / Gradle / Ivy
/*
* Copyright (c) 2018-2023, Antonio Gabriel Muñoz Conejo
* Distributed under the terms of the MIT License
*/
package com.github.tonivade.purefun.free;
import static com.github.tonivade.purefun.Precondition.checkNonNull;
import static com.github.tonivade.purefun.free.FreeApOf.toFreeAp;
import static com.github.tonivade.purefun.free.FreeOf.toFree;
import static com.github.tonivade.purefun.type.ConstOf.toConst;
import static java.util.Collections.singletonList;
import java.util.ArrayDeque;
import java.util.Deque;
import com.github.tonivade.purefun.Applicable;
import com.github.tonivade.purefun.Function1;
import com.github.tonivade.purefun.HigherKind;
import com.github.tonivade.purefun.Kind;
import com.github.tonivade.purefun.Witness;
import com.github.tonivade.purefun.type.Const_;
import com.github.tonivade.purefun.typeclasses.Applicative;
import com.github.tonivade.purefun.typeclasses.FunctionK;
@HigherKind
public sealed interface FreeAp extends FreeApOf, Applicable, A> {
@Override
FreeAp map(Function1 super A, ? extends B> mapper);
@Override
default FreeAp ap(Kind, Function1 super A, ? extends B>> apply) {
if (apply instanceof Pure> pure) {
return map(pure.value);
}
return apply(this, apply);
}
default Kind fold(Applicative applicative) {
return foldMap(FunctionK.identity(), applicative);
}
default FreeAp compile(FunctionK transformer) {
return foldMap(functionKF(transformer), applicativeF()).fix(toFreeAp());
}
default FreeAp flatCompile(
FunctionK> functionK, Applicative> applicative) {
return foldMap(functionK, applicative).fix(toFreeAp());
}
default M analyze(FunctionK> functionK, Applicative> applicative) {
return foldMap(functionK, applicative).fix(toConst()).get();
}
default Free monad() {
return foldMap(Free.functionKF(FunctionK.identity()), Free.monadF()).fix(toFree());
}
@SuppressWarnings({"rawtypes", "unchecked"})
default Kind foldMap(FunctionK functionK, Applicative applicative) {
Deque argsF = new ArrayDeque<>(singletonList(this));
Deque fns = new ArrayDeque<>();
while (true) {
FreeAp argF = argsF.pollFirst();
if (argF instanceof Apply) {
int lengthInitial = argsF.size();
do {
Apply ap = (Apply) argF;
argsF.addFirst(ap.value);
argF = ap.apply;
} while (argF instanceof Apply);
int argc = argsF.size() - lengthInitial;
fns.addFirst(new CurriedFunction(foldArg(argF, functionK, applicative), argc));
} else {
Kind argT = foldArg(argF, functionK, applicative);
if (!fns.isEmpty()) {
CurriedFunction function = fns.pollFirst();
Kind res = applicative.ap(argT, function.value);
if (function.remaining > 1) {
fns.addFirst(new CurriedFunction(res, function.remaining - 1));
} else {
if (!fns.isEmpty()) {
do {
function = fns.pollFirst();
res = applicative.ap(res, function.value);
if (function.remaining > 1) {
fns.addFirst(new CurriedFunction(res, function.remaining - 1));
}
} while (function.remaining == 1 && !fns.isEmpty());
}
if (fns.isEmpty()) {
return res;
}
}
} else {
return argT;
}
}
}
}
static FreeAp pure(T value) {
return new FreeAp.Pure<>(value);
}
static FreeAp lift(Kind value) {
return new FreeAp.Lift<>(value);
}
static FreeAp apply(Kind, ? extends T> value,
Kind, ? extends Function1 super T, ? extends R>> mapper) {
return new FreeAp.Apply<>(value.fix(toFreeAp()), mapper.fix(toFreeAp()));
}
static FunctionK> functionKF(FunctionK functionK) {
return new FunctionK<>() {
@Override
public FreeAp apply(Kind from) {
return lift(functionK.apply(from));
}
};
}
@SuppressWarnings("unchecked")
static Applicative> applicativeF() {
return FreeApplicative.INSTANCE;
}
private static Kind foldArg(
FreeAp argF, FunctionK transformation, Applicative applicative) {
if (argF instanceof Pure pure) {
return applicative.pure(pure.value);
}
if (argF instanceof Lift lift) {
return transformation.apply(lift.value);
}
throw new IllegalStateException();
}
final class Pure implements FreeAp {
private final A value;
private Pure(A value) {
this.value = checkNonNull(value);
}
@Override
public FreeAp map(Function1 super A, ? extends B> mapper) {
return pure(mapper.apply(value));
}
@Override
public String toString() {
return "Pure(" + value + ')';
}
}
final class Lift implements FreeAp {
private final Kind value;
private Lift(Kind value) {
this.value = checkNonNull(value);
}
@Override
public FreeAp map(Function1 super A, ? extends B> mapper) {
return apply(this, pure(mapper));
}
@Override
public String toString() {
return "Lift(" + value + ')';
}
}
final class Apply implements FreeAp {
private final FreeAp value;
private final FreeAp> apply;
private Apply(
FreeAp value,
FreeAp> apply) {
this.value = checkNonNull(value);
this.apply = checkNonNull(apply);
}
@Override
public FreeAp map(Function1 super B, ? extends C> mapper) {
return apply(this, pure(mapper));
}
@Override
public String toString() {
return "Apply(" + value + ", ...)";
}
}
record CurriedFunction(Kind> value, int remaining) {
public CurriedFunction {
checkNonNull(value);
}
}
}
interface FreeApplicative extends Applicative> {
@SuppressWarnings("rawtypes")
FreeApplicative INSTANCE = new FreeApplicative() {};
@Override
default FreeAp pure(T value) {
return FreeAp.pure(value);
}
@Override
default FreeAp ap(
Kind, ? extends T> value,
Kind, ? extends Function1 super T, ? extends R>> apply) {
return FreeAp.apply(value, apply);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy