Last active
August 29, 2015 14:22
-
-
Save orionll/c9a4c81445d492abe7c2 to your computer and use it in GitHub Desktop.
Foldable typeclass in Java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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