Skip to content

Instantly share code, notes, and snippets.

@orionll
Last active August 29, 2015 14:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save orionll/c9a4c81445d492abe7c2 to your computer and use it in GitHub Desktop.
Save orionll/c9a4c81445d492abe7c2 to your computer and use it in GitHub Desktop.
Foldable typeclass in Java
import static fj.data.Option.none;
import static fj.data.Option.some;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.LinkedList;
import fj.*;
import fj.data.*;
import fj.data.List.Buffer;
import fj.data.vector.*;
import fj.function.Effect1;
/**
* Class of data structures that can be folded.
*
* <p>Minimal complete definition: <code>toIterable</code> or <code>foldLeft(T, F2, B)</code>
* or <code>foldRight(T, F2, B)</code>. Each method can be overridden in subclasses for better
* performance.
*/
public abstract class Fold<A, T> {
public Iterable<A> toIterable(final T t) {
return toStream(t).toCollection();
}
public <B> B foldLeft(final T t, final F2<B, A, B> f, final B z) {
B b = z;
for (A a : toIterable(t)) {
b = f.f(b, a);
}
return b;
}
public <B> B foldRight(final T t, final F2<A, P1<B>, B> f, final B z) {
ArrayList<A> arrayList = toArrayList(t);
B b = z;
for (int i = arrayList.size() - 1; i >= 0; i--) {
b = f.f(arrayList.get(i), P.p(b));
}
return b;
}
public <B> B foldLeft(final T t, final F<B, F<A, B>> f, final B z) {
return foldLeft(t, Function.uncurryF2(f), z);
}
public <B> B foldRight(final T t, final F<A, F<P1<B>, B>> f, final B z) {
return foldRight(t, Function.uncurryF2(f), z);
}
public <M> M foldMap(final T t, final F<A, M> f, final Monoid<M> m) {
return foldLeft(t, (b, a) -> m.sum(b, f.f(a)), m.zero());
}
public A fold(final T t, final Monoid<A> m) {
return foldMap(t, Function.identity(), m);
}
public void foreach(final T t, final Effect1<A> f) {
for (A a : toIterable(t)) {
f.f(a);
}
}
public int length(final T t) {
return foldLeft(t, (arr, __) -> { arr[0]++; return arr; }, new int[1])[0];
}
public Option<A> find(final T t, final F<A, Boolean> predicate) {
for (A a : toIterable(t)) {
if (predicate.f(a)) {
return some(a);
}
}
return none();
}
public boolean exists(final T t, final F<A, Boolean> predicate) {
return find(t, predicate).isSome();
}
public boolean forall(final T t, final F<A, Boolean> predicate) {
return !exists(t, a -> !predicate.f(a));
}
public boolean contains(final T t, final Equal<A> eq, final A elem) {
return exists(t, a -> eq.eq(a, elem));
}
public int count(final T t, final F<A, Boolean> predicate) {
int count = 0;
for (A a : toIterable(t)) {
if (predicate.f(a)) {
count++;
}
}
return count;
}
public boolean isEmpty(final T t) {
return !toIterable(t).iterator().hasNext();
}
public boolean isNotEmpty(final T t) {
return !isEmpty(t);
}
public List<A> toList(final T t) {
return foldLeft(t, Buffer<A>::snoc, Buffer.empty()).toList();
}
public Stream<A> toStream(final T t) {
return foldRight(t, (F2<A, P1<Stream<A>>, Stream<A>>) Stream::cons, Stream.nil());
}
public Seq<A> toSeq(final T t) {
return foldLeft(t, Seq<A>::snoc, Seq.empty());
}
public Set<A> toSet(final T t, Ord<A> ord) {
return foldLeft(t, (F2<Set<A>, A, Set<A>>) Set<A>::insert, Set.empty(ord));
}
public Array<A> toArray(final T t) {
return Array.array((A[]) toArrayList(t).toArray(new Object[toArrayList(t).size()]));
}
public ArrayList<A> toArrayList(final T t) {
return foldLeft(t, (list, a) -> { list.add(a); return list; }, new ArrayList<A>(0));
}
public LinkedList<A> toLinkedList(final T t) {
return foldLeft(t, (list, a) -> { list.add(a); return list; }, new LinkedList<A>());
}
public static final <A> Fold<A, Iterable<A>> iterableFold() {
return new Fold<A, Iterable<A>>() {
@Override
public Iterable<A> toIterable(final Iterable<A> t) {
return t;
}
};
}
public static final <A> Fold<A, List<A>> listFold() {
return new Fold<A, List<A>>() {
@Override public Stream<A> toStream(final List<A> t) { return t.toStream(); }
@Override public List<A> toList(final List<A> t) { return t; }
@Override public Iterable<A> toIterable(final List<A> t) { return t; }
};
}
public static final <A> Fold<A, Stream<A>> streamFold() {
return new Fold<A, Stream<A>>() {
@Override public <B> B foldRight(final Stream<A> t, final F2<A, P1<B>, B> f, final B z) { return t.foldRight(f, z); }
@Override public Stream<A> toStream(final Stream<A> t) { return t; }
@Override public Iterable<A> toIterable(final Stream<A> t) { return t; }
};
}
public static final <A> Fold<A, Seq<A>> seqFold() {
return new Fold<A, Seq<A>>() {
@Override public int length(final Seq<A> t) { return t.length(); }
@Override public Seq<A> toSeq(final Seq<A> t) { return t; }
@Override public Iterable<A> toIterable(final Seq<A> t) { return t; }
};
}
public static final <A> Fold<A, Set<A>> setFold() {
return new Fold<A, Set<A>>() {
@Override public Iterable<A> toIterable(final Set<A> t) { return t; }
@Override public int length(final Set<A> t) { return t.size(); }
@Override public Set<A> toSet(final Set<A> t, final Ord<A> ord) { return (t.ord() == ord) ? t : super.toSet(t, ord); }
};
}
public static final <A> Fold<A, Option<A>> optionFold() {
return new Fold<A, Option<A>>() {
@Override public Iterable<A> toIterable(final Option<A> t) { return t; }
};
}
public static final <A> Fold<A, ArrayList<A>> arrayListFold() {
return new Fold<A, ArrayList<A>>() {
@Override public Iterable<A> toIterable(final ArrayList<A> t) { return t; }
@Override public int length(final ArrayList<A> t) { return t.size(); }
@Override public ArrayList<A> toArrayList(final ArrayList<A> t) { return t; }
};
}
public static final <A> Fold<A, LinkedList<A>> linkedListFold() {
return new Fold<A, LinkedList<A>>() {
@Override public Iterable<A> toIterable(final LinkedList<A> t) { return t; }
@Override public int length(final LinkedList<A> t) { return t.size(); }
@Override public LinkedList<A> toLinkedList(final LinkedList<A> t) { return t; }
};
}
public static final <A> Fold<A, Array<A>> arrayFold() {
return new Fold<A, Array<A>>() {
@Override public Iterable<A> toIterable(final Array<A> t) { return t; }
@Override public int length(final Array<A> t) { return t.length(); }
};
}
public static final <A> Fold<A, V2<A>> v2Fold() {
return new Fold<A, V2<A>>() {
@Override public Iterable<A> toIterable(final V2<A> t) { return t; }
@Override public int length(final V2<A> t) { return 2; }
};
}
public static final <A> Fold<A, V3<A>> v3Fold() {
return new Fold<A, V3<A>>() {
@Override public Iterable<A> toIterable(final V3<A> t) { return t; }
@Override public int length(final V3<A> t) { return 3; }
};
}
public static final <A> Fold<A, V4<A>> v4Fold() {
return new Fold<A, V4<A>>() {
@Override public int length(final V4<A> t) { return 4; }
@Override public Iterable<A> toIterable(final V4<A> t) { return t; }
};
}
public static final <A> Fold<A, V5<A>> v5Fold() {
return new Fold<A, V5<A>>() {
@Override public int length(final V5<A> t) { return 5; }
@Override public Iterable<A> toIterable(final V5<A> t) { return t; }
};
}
public static final <A> Fold<A, V6<A>> v6Fold() {
return new Fold<A, V6<A>>() {
@Override public int length(final V6<A> t) { return 6; }
@Override public Iterable<A> toIterable(final V6<A> t) { return t; }
};
}
public static final <A> Fold<A, V7<A>> v7Fold() {
return new Fold<A, V7<A>>() {
@Override public int length(final V7<A> t) { return 7; }
@Override public Iterable<A> toIterable(final V7<A> t) { return t; }
};
}
public static final <A> Fold<A, V8<A>> v8Fold() {
return new Fold<A, V8<A>>() {
@Override public int length(final V8<A> t) { return 8; }
@Override public Iterable<A> toIterable(final V8<A> t) { return t; }
};
}
public static final Fold<Character, String> stringFold() {
return new Fold<Character, String>() {
@Override public int length(final String t) { return t.length(); }
@Override
public Iterable<Character> toIterable(final String t) {
return new AbstractList<Character>() {
@Override
public Character get(final int index) {
return t.charAt(index);
}
@Override
public int size() {
return t.length();
}
};
}
@Override
public <B> B foldLeft(final String t, final F2<B, Character, B> f, final B z) {
B b = z;
for (char c : t.toCharArray()) {
b = f.f(b, c);
}
return b;
}
};
}
public static final Fold<Character, LazyString> lazyStringFold() {
return new Fold<Character, LazyString>() {
@Override public Iterable<Character> toIterable(final LazyString t) { return t.toStream(); }
};
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment