com.github.tonivade.purefun.free.Cofree Maven / Gradle / Ivy
/*
* Copyright (c) 2018-2020, Antonio Gabriel Muñoz Conejo
* Distributed under the terms of the MIT License
*/
package com.github.tonivade.purefun.free;
import com.github.tonivade.purefun.Function1;
import com.github.tonivade.purefun.Function2;
import com.github.tonivade.purefun.Higher1;
import com.github.tonivade.purefun.HigherKind;
import com.github.tonivade.purefun.Kind;
import com.github.tonivade.purefun.Operator2;
import com.github.tonivade.purefun.type.Eval;
import com.github.tonivade.purefun.typeclasses.Applicative;
import com.github.tonivade.purefun.typeclasses.Functor;
import com.github.tonivade.purefun.typeclasses.Monoid;
import com.github.tonivade.purefun.typeclasses.Traverse;
import static java.util.Objects.requireNonNull;
@HigherKind
public final class Cofree {
private final Functor functor;
private final A head;
private final Eval>> tail;
private Cofree(Functor functor, A head, Eval>> tail) {
this.functor = requireNonNull(functor);
this.head = requireNonNull(head);
this.tail = requireNonNull(tail);
}
public A extract() {
return head;
}
public Higher1> tailForced() {
return tail.value();
}
public Cofree runTail() {
return of(functor, head, Eval.now(tail.value()));
}
public Cofree run() {
return of(functor, head, Eval.now(transformTail(Cofree::run).value()));
}
public Cofree map(Function1 mapper) {
return transform(mapper, c -> c.map(mapper));
}
public Cofree coflatMap(Function1, B> mapper) {
return of(functor, mapper.apply(this), transformTail(c -> c.coflatMap(mapper)));
}
// XXX: remove eval applicative instance parameter, if instances project is added then cyclic dependency problem
public Eval fold(Applicative applicative, Traverse traverse, Function2, Eval> mapper) {
Eval> eval =
traverse.traverse(applicative, tailForced(), c -> c.fold(applicative, traverse, mapper).kind1())
.fix1(Eval::narrowK);
return eval.flatMap(fb -> mapper.apply(extract(), fb));
}
public Eval reduce(Applicative applicative, Traverse traverse,
Function1 initial, Operator2 combine) {
return fold(applicative, traverse,
(a, fb) -> Eval.later(() -> traverse.fold(Monoid.of(initial.apply(a), combine), fb)));
}
public Eval reduceToString(Applicative applicative, Traverse traverse, Operator2 join) {
return reduce(applicative, traverse, String::valueOf, join);
}
public Cofree transform(Function1 headMap, Function1, Cofree> tailMap) {
return of(functor, transformHead(headMap), transformTail(tailMap));
}
private B transformHead(Function1 headMap) {
return headMap.apply(head);
}
private Eval>> transformTail(Function1, Cofree> tailMap) {
return tail.map(t -> functor.map(t, tailMap));
}
public static Cofree unfold(Functor functor, A head, Function1> unfold) {
return of(functor, head, Eval.later(() -> functor.map(unfold.apply(head), a -> unfold(functor, a, unfold))));
}
public static Cofree of(Functor functor, A head, Eval>> tail) {
return new Cofree<>(functor, head, tail);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy