package fmlist; import fj.F; import fj.F2; import fj.F3; import fj.Function; import fj.Monoid; import fj.data.Either; abstract class FM { abstract boolean couldBeFinite(); abstract X fm(Monoid monoid, F mapFunc); F2, F, X> fm() { final FM self = this; return new F2, F, X>() { @Override public X f(Monoid a, F b) { return self.fm(a, b); } }; } F, X> fm(Monoid monoid) { final Monoid qm = monoid; final FM self = this; return new F, X>() { @Override public X f(F a) { return self.fm(qm, a); } }; } static F3, F, FM, X> fm_() { return new F3, F, FM, X>() { @Override public X f(Monoid a, F b, FM c) { return c.fm(a, b); } }; } static FM newFM() { return new FM() { @Override X fm(Monoid monoid, F mapFunc) { return monoid.zero(); } @Override boolean couldBeFinite() { return true; } }; } static FM newFM(E e) { final E k = e; return new FM() { @Override X fm(Monoid monoid, F mapFunc) { return mapFunc.f(k); } @Override boolean couldBeFinite() { return true; } }; } static FM newFM(Iterable c) { final Iterable i = c; return new FM() { @Override X fm(Monoid monoid, F mapFunc) { X z = monoid.zero(); for (E x : i) { X q = mapFunc.f(x); z = monoid.sum(q, z); } return z; } @Override boolean couldBeFinite() { return true; } }; } FM appendFM(FM other) { return FM.appendFM(this, other); } static FM appendFM(FM fm1, FM fm2) { final FM fmA = fm1; final FM fmB = fm2; return new FM() { @Override X fm(Monoid monoid, F mapFunc) { return monoid.sum(fmA.fm(monoid, mapFunc), fmB.fm(monoid, mapFunc)); } @Override boolean couldBeFinite() { return fmA.couldBeFinite() && fmB.couldBeFinite(); } }; } static F2, FM, FM> appendFM() { return new F2, FM, FM>() { @Override public FM f(FM a, FM b) { return FM.appendFM(a, b); } }; } FM transform(TransformFunc tf) { final FM self = this; final TransformFunc func = tf; return new FM() { @Override X fm(Monoid monoid, F mapFunc) { return self.fm(monoid, func.f(monoid, mapFunc)); } @Override boolean couldBeFinite() { return true; } }; } FM transformCS(TransformCSFunc tcf, S s) { final FMList l = new FMList(this); final TransformCSFunc t = tcf; final S s0 = s; return new FM() { @Override X fm(Monoid monoid, F mapFunc) { final Monoid m1 = monoid; final Monoid> m2 = Monoid.functionMonoid(monoid); final F mf = mapFunc; final F3, X, S, X> a3 = new F3, X, S, X>() { @Override public X f(F a, X b, S c) { return m1.sum(b, a.f(c)); } }; final F2, F> a2 = new F2, F>() { @Override public F f(E a, F b) { return t.f(m1, mf, a, Function.uncurryF2(Function.curry(a3).f(b))); } }; return l.foldr(a2, m2.zero()).f(s0); } @Override boolean couldBeFinite() { return true; } }; } static FM unfold(F>> unfoldFunc, N seedValue) { final F>> g = unfoldFunc; return g.andThen(new F>, FM>() { @Override public FM f(FM> a) { final FM> z = a; return z.transform(new TransformFunc>() { @Override M f(Monoid monoid, F func, Either val) { final F3, F, FM, M> fmi = fm_(); if (val.isLeft()) { return fmi.f(monoid, func, unfold(g, val.left().value())); } else { return func.f(val.right().value()); } } }); } }).f(seedValue); } static F> unfold(F>> unfoldFunc) { final F>> g = unfoldFunc; return new F>() { @Override public FM f(N a) { return unfold(g, a); } }; } static F2>>, N, FM> unfold() { return new F2>>, N, FM>() { @Override public FM f(F>> a, N b) { return unfold(a, b); } }; } }