package water.util.fp;
import java.util.*;
/**
* Elements of Functional Programming (known as FP) in Java
*
* @see <a href="https://en.wikipedia.org/wiki/Functional_programming">Wikipedia</a>
* for details
*/
public class FP {
// the following two borrowed from Java 7 library.
public static boolean equal(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}
public static int hashCode(Object o) {
return o != null ? o.hashCode() : 0;
}
interface Option<T> extends Iterable<T> {
boolean isEmpty();
boolean nonEmpty();
<U> Option<U> flatMap(Function<T, Option<U>> f);
}
public final static Option<?> None = new Option<Object>() {
@Override public boolean isEmpty() { return true; }
@Override public boolean nonEmpty() { return false; }
@SuppressWarnings("unchecked")
@Override public <U> Option<U> flatMap(Function<Object, Option<U>> f) {
return (Option<U>) None;
}
@Override public Iterator<Object> iterator() {
return Collections.emptyList().iterator();
}
@Override public String toString() { return "None"; }
@Override public int hashCode() { return -1; }
};
public final static class Some<T> implements Option<T> {
private List<T> contents;
public Some(T t) { contents = Collections.singletonList(t); }
@Override public boolean isEmpty() { return false; }
@Override public boolean nonEmpty() { return true; }
@Override
public <U> Option<U> flatMap(Function<T, Option<U>> f) {
return f.apply(get());
}
@Override public Iterator<T> iterator() {
return contents.iterator();
}
@SuppressWarnings("unchecked")
public T get() { return contents.get(0); }
@Override public String toString() { return "Some(" + get() + ")"; }
@Override public boolean equals(Object o) {
return this == o ||
(o instanceof Some && equal(get(), (((Some<?>) o).get())));
}
@Override public int hashCode() { return FP.hashCode(get()); }
}
public static <T> Option<T> Some(T t) {
return new Some<>(t);
}
@SuppressWarnings("unchecked")
public static <T> Option<T> Option(T t) {
return t == null ? (Option<T>)None : new Some(t);
}
@SuppressWarnings("unchecked")
public static <T> Option<T> flatten(Option<Option<T>> optOptT) {
return optOptT.isEmpty() ? (Option<T>)None : ((Some<Option<T>>)optOptT).get();
}
public static <T> Option<T> headOption(Iterator<T> it) {
return Option(it.hasNext() ? it.next() : null);
}
public static <T> Option<T> headOption(Iterable<T> ts) {
return headOption(ts.iterator());
}
}