package cyclops.control; import com.oath.cyclops.hkt.Higher; import com.oath.cyclops.hkt.Higher4; import com.oath.cyclops.hkt.DataWitness.rws; import com.oath.cyclops.hkt.DataWitness.supplier; import cyclops.free.Free; import cyclops.function.*; import cyclops.kinds.SupplierKind; import lombok.AccessLevel; import lombok.AllArgsConstructor; import cyclops.data.tuple.Tuple; import cyclops.data.tuple.Tuple3; import java.util.function.BiFunction; import java.util.function.Function; import static cyclops.data.tuple.Tuple.tuple; @AllArgsConstructor(access = AccessLevel.PRIVATE) public final class ReaderWriterState<R,W,S,T> implements Higher4<rws,R,W,S,T>{ private final Monoid<W> monoid; private final BiFunction<R,S, Free<supplier,Tuple3<W, S, T>>> runState; public Tuple3<W,S,T> run(R r,S s) { return SupplierKind.run(runState.apply(r,s)); } public static <T,R1, W, S, R> ReaderWriterState<R1, W, S, R> tailRec(Monoid<W> monoid,T initial, Function<? super T, ? extends ReaderWriterState<R1, W, S, ? extends Either<T, R>>> fn) { Higher<Higher<Higher<Higher<rws, R1>, W>, S>, R> x = ReaderWriterState.tailRecInternal(monoid,initial, fn); return narrowK(x); } private static <T,R1, W, S, R> Higher<Higher<Higher<Higher<rws, R1>, W>, S>, R> tailRecInternal(Monoid<W> monoid,T initial, Function<? super T, ? extends Higher<Higher<Higher<Higher<rws, R1>, W>, S>, ? extends Either<T, R>>> fn) { return narrowK(fn.apply(initial)).flatMap( eval -> eval.fold(s->narrowK(tailRecInternal(monoid,s,fn)), p->{ ReaderWriterState<R1, W, S, R> k = narrowK(rws((a,s)-> tuple(monoid.zero(),s,p),monoid)); return k; })); } public ReaderWriterState<R,W,S,T> tell(W value) { BiFunction<? super R, ? super S, Free<supplier,Tuple3<W,S, T>>> fn = (r,s)->runState.apply(r,s).map(t3-> tuple(monoid.apply(t3._1(),value),t3._2(),t3._3())); return suspended(fn,monoid); } public ReaderWriterState<R,W,S,T> ask() { return suspended((r,s) -> runState.apply(r,s).map(t3 -> Tuple.<W,S,T>tuple(monoid.zero(),s,t3._3())),monoid); } public ReaderWriterState<R,W,S,T> local(Function<? super R,? extends R> fn) { BiFunction<? super R, ? super S, Free<supplier,Tuple3<W,S, T>>> runFn = (R r, S s) -> runState.apply(fn.apply(r), s); return suspended(runFn,monoid); } public <R2> ReaderWriterState<R,W,S,R2> map(Function<? super T,? extends R2> mapper) { return mapState(t -> tuple(t._1(), t._2(), mapper.apply(t._3()))); } public <R2> ReaderWriterState<R,W,S,R2> mapState(Function<Tuple3<W,S,T>, Tuple3<W,S, R2>> fn) { return suspended((r,s) -> runState.apply(r,s).map(t3 -> fn.apply(t3)),monoid); } private static <R,W,S,T> ReaderWriterState<R,W,S,T> suspended(BiFunction<? super R, ? super S, Free<supplier,Tuple3<W,S, T>>> runF, Monoid<W> monoid) { return new ReaderWriterState<R, W, S, T>(monoid,(R r ,S s) -> SupplierKind.suspend(SupplierKind.λK(()->runF.apply(r,s)))); } public <R2> ReaderWriterState<R,W,S,R2> flatMap(Function<? super T,? extends ReaderWriterState<R,W,S,R2>> f) { return suspended((r,s) -> runState.apply(r, s) .flatMap(result -> Free.done(f.apply(result._3()) .run(r, result._2()) .transform((w2,s2,r2)-> tuple(monoid.apply(w2,result._1()),s2,r2) ))),monoid); } public <R1, R2, R3, R4> ReaderWriterState<R,W,S,R4> forEach4(Function<? super T, ReaderWriterState<R,W,S,R1>> value2, BiFunction<? super T, ? super R1, ReaderWriterState<R,W,S,R2>> value3, Function3<? super T, ? super R1, ? super R2, ReaderWriterState<R,W,S,R3>> value4, Function4<? super T, ? super R1, ? super R2, ? super R3, ? extends R4> yieldingFunction) { return this.flatMap(in -> { ReaderWriterState<R,W,S,R1> a = value2.apply(in); return a.flatMap(ina -> { ReaderWriterState<R,W,S,R2> b = value3.apply(in,ina); return b.flatMap(inb -> { ReaderWriterState<R,W,S,R3> c = value4.apply(in,ina,inb); return c.map(inc->yieldingFunction.apply(in, ina, inb, inc)); }); }); }); } public <R1, R2, R4> ReaderWriterState<R,W,S,R4> forEach3(Function<? super T, ReaderWriterState<R,W,S,R1>> value2, BiFunction<? super T, ? super R1, ReaderWriterState<R,W,S,R2>> value3, Function3<? super T, ? super R1, ? super R2, ? extends R4> yieldingFunction) { return this.flatMap(in -> { ReaderWriterState<R,W,S,R1> a = value2.apply(in); return a.flatMap(ina -> { ReaderWriterState<R,W,S,R2> b = value3.apply(in,ina); return b.map(in2 -> { return yieldingFunction.apply(in, ina, in2); }); }); }); } public <R1, R4> ReaderWriterState<R,W,S,R4> forEach2(Function<? super T, ReaderWriterState<R,W,S,R1>> value2, BiFunction<? super T, ? super R1, ? extends R4> yieldingFunction) { return this.flatMap(in -> { ReaderWriterState<R,W,S,R1> a = value2.apply(in); return a.map(in2 -> { return yieldingFunction.apply(in, in2); }); }); } public static <R,W,S,T> ReaderWriterState<R,W,S,T> rws(BiFunction<? super R, ? super S,? extends Tuple3<W,S, T>> runF, Monoid<W> monoid) { return new ReaderWriterState<R, W, S, T>(monoid,(r,s) -> Free.done(runF.apply(r,s))); } public static <R,W,S,T> ReaderWriterState<R,W,S,T> narrowK(Higher<Higher<Higher<Higher<rws, R>, W>, S>, T> hkt){ return (ReaderWriterState<R,W,S,T>)hkt; } public static <R,W,S,T> Higher<Higher<Higher<Higher<rws, R>, W>, S>, T> widen(ReaderWriterState<R,W,S,T> narrow) { return narrow; } }