package no.java.incogito;
import fj.Bottom;
import static fj.Bottom.error;
import fj.F;
import fj.F2;
import fj.F3;
import static fj.Function.curry;
import static fj.P.p;
import fj.P1;
import fj.P2;
import fj.P3;
import fj.data.Either;
import static fj.data.Either.left;
import static fj.data.Either.right;
import fj.data.List;
import static fj.data.List.cons;
import static fj.data.List.list;
import fj.data.Option;
import static fj.data.Option.none;
import static fj.data.Option.some;
import fj.data.Stream;
import fj.data.TreeMap;
import fj.pre.Ord;
import fj.pre.Show;
import static fj.pre.Show.show;
import org.joda.time.LocalDate;
import java.io.File;
import java.io.FileFilter;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* @author <a href="mailto:trygvis@java.no">Trygve Laugstøl</a>
* @version $Id$
*/
public class Functions {
// -----------------------------------------------------------------------
// java.lang.Double
// -----------------------------------------------------------------------
public static final F<String, Either<NumberFormatException, Double>> parseDouble = new F<String, Either<NumberFormatException, Double>>() {
public Either<NumberFormatException, Double> f(String s) {
try {
return right(Double.parseDouble(s));
} catch (NumberFormatException e) {
return left(e);
}
}
};
// -----------------------------------------------------------------------
// java.lang.Strings
// -----------------------------------------------------------------------
public static final F<String, F<String, Boolean>> equals = curry(new F2<String, String, Boolean>() {
public Boolean f(String s, String s1) {
return s.equals(s1);
}
});
public static final F<String, F<String, Boolean>> String_startsWith = curry(new F2<String, String, Boolean>() {
public Boolean f(String s, String s1) {
return s1.startsWith(s);
}
});
public static final F<String, F<String, Boolean>> String_endsWith = curry(new F2<String, String, Boolean>() {
public Boolean f(String s, String s1) {
return s1.endsWith(s);
}
});
public static final F<String, F<String, List<String>>> split = curry(new F2<String, String, List<String>>() {
public List<String> f(String regex, String string) {
return list(string.split(regex));
}
});
public static final F<String, String> trim = new F<String, String>() {
public String f(String s) {
return s.trim();
}
};
/**
* f a b = a + b
*/
public static final F<String, F<String, String>> append = curry(new F2<String, String, String>() {
public String f(String a, String b) {
return b.concat(a);
}
});
/**
* f a b = a + b
*/
public static final F<String, F<String, F<String, String>>> String_join = curry(new F3<String, String, String, String>() {
public String f(String join, String s1, String s2) {
return s1 + join + s2;
}
});
/**
* f a b = b + a
*/
public static final F<String, F<String, String>> prepend = curry(new F2<String, String, String>() {
public String f(String a, String b) {
return a.concat(b);
}
});
public static final F<Integer, F<String, String>> substringFrom = curry(new F2<Integer, String, String>() {
public String f(Integer beginIndex, String s) {
return s.substring(beginIndex);
}
});
public static final F<Integer, F<Integer, F<String, String>>> substring = curry(new F3<Integer, Integer, String, String>() {
public String f(Integer beginIndex, Integer endIndex, String s) {
return s.substring(beginIndex, endIndex);
}
});
// -----------------------------------------------------------------------
// java.io.File
// -----------------------------------------------------------------------
public static final F<String, File> newRelativeFile = new F<String, File>() {
public File f(String s) {
return new File(s);
}
};
public static final F<File, F<String, File>> newFile = curry(new F2<File, String, File>() {
public File f(File file, String s) {
return new File(file, s);
}
});
public static final F<File, Boolean> File_canRead = new F<File, Boolean>() {
public Boolean f(File file) {
return file.canRead();
}
};
public static final F<File, Boolean> File_isDirectory = new F<File, Boolean>() {
public Boolean f(File file) {
return file.isDirectory();
}
};
public static final F<File, F<FileFilter, List<File>>> listFilesWithFileFilter = curry(new F2<File, FileFilter, List<File>>() {
public List<File> f(File file, FileFilter fileFilter) {
return list(file.listFiles(fileFilter));
}
});
public static final F<File, List<File>> File_listFiles = new F<File, List<File>>() {
public List<File> f(File file) {
File[] files = file.listFiles();
return files == null ? List.<File>nil() : list(files);
}
};
public static final F<File, String> File_getName = new F<File, String>() {
public String f(File file) {
return file.getName();
}
};
public static final F<File, String> File_getAbsolutePath = new F<File, String>() {
public String f(File file) {
return file.getAbsolutePath();
}
};
public static final Show<File> File_show = Show.showS(File_getName);
public static final Show<File> File_showAbsolute = Show.showS(File_getAbsolutePath);
public static Ord<LocalDate> LocalDate_ord = Ord.comparableOrd();
// -----------------------------------------------------------------------
// fj.data.Either
// -----------------------------------------------------------------------
public static <R> R throwLeft(Either<Exception, R> either) throws Exception {
if (either.isLeft()) {
throw either.left().value();
}
return either.right().value();
}
public static <A, B> F<Either<A, B>, Option<B>> Either_rightToOption_() {
return new F<Either<A, B>, Option<B>>() {
public Option<B> f(Either<A, B> abEither) {
return abEither.right().toOption();
}
};
}
// -----------------------------------------------------------------------
// fj.data.Option
// -----------------------------------------------------------------------
// I'll get killed for this - trygve
public static <A> A toNull(Option<A> option) {
return option.isSome() ? option.some() : null;
}
public static <A, B> F<Option<A>, Option<B>> Option_map(final F<A, B> f) {
return new F<Option<A>, Option<B>>() {
public Option<B> f(Option<A> option) {
return option.map(f);
}
};
}
public static <A> F<Option<A>, A> Option_somes() {
return new F<Option<A>, A>() {
public A f(Option<A> option) {
return option.some();
}
};
}
public static <A> F<Option<Option<A>>, Option<A>> Option_join_() {
return new F<Option<Option<A>>, Option<A>>() {
public Option<A> f(Option<Option<A>> option) {
return Option.join(option);
}
};
}
public static <A> A Option_valueE(Option<A> option, String e) {
if (option.isNone()) {
throw Bottom.error(e);
}
return option.some();
}
// -----------------------------------------------------------------------
// fj.data.TreeMap
// -----------------------------------------------------------------------
public static <K, V> F<K, F<TreeMap<K, V>, Option<V>>> TreeMap_get() {
return new F<K, F<TreeMap<K, V>, Option<V>>>() {
public F<TreeMap<K, V>, Option<V>> f(final K k) {
return new F<TreeMap<K, V>, Option<V>>() {
public Option<V> f(TreeMap<K, V> map) {
return map.get(k);
}
};
}
};
}
public static <K, V> F<F<V, K>, F<TreeMap<K, V>, F<V, TreeMap<K, V>>>> TreeMap_set() {
return curry(new F3<F<V, K>, TreeMap<K, V>, V, TreeMap<K, V>>() {
public TreeMap<K, V> f(F<V, K> vkf, TreeMap<K, V> treeMap, V v) {
return treeMap.set(vkf.f(v), v);
}
});
}
// -----------------------------------------------------------------------
// fj.data.List
// -----------------------------------------------------------------------
public static <T> F<List<T>, T> head_() {
return new F<List<T>, T>() {
public T f(List<T> list) {
return list.head();
}
};
}
public static <T> F<List<T>, Option<T>> List_toOption_() {
return new F<List<T>, Option<T>>() {
public Option<T> f(List<T> list) {
return list.toOption();
}
};
}
public static <A> F<F<A, Boolean>, F<List<A>, List<A>>> List_filter() {
return curry(new F2<F<A, Boolean>, List<A>, List<A>>() {
public List<A> f(F<A, Boolean> filter, List<A> list) {
return list.filter(filter);
}
});
}
public static <A, B, C> List<C> List_product(List<A> as, final List<B> bs, final F<A, F<B, C>> f) {
class State {
final A a;
final Iterator<A> ai;
final Iterator<B> bi;
State(A a, Iterator<A> ai, Iterator<B> bi) {
this.a = a;
this.ai = ai;
this.bi = bi;
}
}
if (as.isEmpty() || bs.isEmpty()) {
return List.nil();
}
Iterator<A> ai = as.iterator();
return List.unfold(new F<State, Option<P2<C, State>>>() {
public Option<P2<C, State>> f(State state) {
// Still running Bs
if (state.bi.hasNext()) {
C c = f.f(state.a).f(state.bi.next());
return some(p(c, new State(state.a, state.ai, state.bi)));
}
// Out of Bs
if (state.ai.hasNext()) {
A a = state.ai.next();
Iterator<B> bi = bs.iterator();
C c = f.f(a).f(bi.next());
return some(p(c, new State(a, state.ai, bi)));
}
// Out of As
return none();
}
}, new State(ai.next(), ai, bs.iterator()));
}
public static <A> Iterator<A> List_iterator(final List<A> l) {
return new Iterator<A>() {
List<A> list = l;
public boolean hasNext() {
return list.isEmpty();
}
public A next() {
if (list.isEmpty()) {
throw new NoSuchElementException();
}
A head = list.head();
list = list.tail();
return head;
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
// -----------------------------------------------------------------------
// fj.data.Stream
// -----------------------------------------------------------------------
public static <A> Stream<A> Stream_cycle(final Stream<A> stream) {
if (stream.isEmpty())
throw error("cycle on empty list");
return Stream.unfold(new F<Iterator<A>, Option<P2<A, Iterator<A>>>>() {
public Option<P2<A, Iterator<A>>> f(Iterator<A> it) {
if (it.hasNext()) {
return some(p(it.next(), it));
}
it = Stream_iterator(stream);
return some(p(it.next(), it));
}
}, Functions.<A>Stream_iterator(stream));
}
public static <A> Iterator<A> Stream_iterator(final Stream<A> s) {
return new Iterator<A>() {
P1<Stream<A>> stream = p(s);
public boolean hasNext() {
return stream._1().isNotEmpty();
}
public A next() {
Stream<A> s = stream._1();
if (s.isEmpty()) {
throw new NoSuchElementException();
}
A head = s.head();
stream = s.tail();
return head;
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
// -----------------------------------------------------------------------
// fj.Function
// -----------------------------------------------------------------------
public static <A, B, C> F<A, C> compose(final F<B, C> g, final F<A, B> f) {
return new F<A, C>() {
public C f(A a) {
return g.f(f.f(a));
}
};
}
public static <A, B, C, D> F<A, D> compose(final F<C, D> h, final F<B, C> g, final F<A, B> f) {
return new F<A, D>() {
public D f(A a) {
return h.f(g.f(f.f(a)));
}
};
}
public static <A, B, C, D, E> F<A, E> compose(final F<D, E> i, final F<C, D> h, final F<B, C> g, final F<A, B> f) {
return new F<A, E>() {
public E f(A a) {
return i.f(h.f(g.f(f.f(a))));
}
};
}
public static <A, B, C, D, E, F$> F<A, F$> compose(final F<E, F$> j, final F<D, E> i, final F<C, D> h, final F<B, C> g, final F<A, B> f) {
return new F<A, F$>() {
public F$ f(A a) {
return j.f(i.f(h.f(g.f(f.f(a)))));
}
};
}
public static <A, B, C, D, E, F$, G> F<A, G> compose(final F<F$, G> k, final F<E, F$> j, final F<D, E> i, final F<C, D> h, final F<B, C> g, final F<A, B> f) {
return new F<A, G>() {
public G f(A a) {
return k.f(j.f(i.f(h.f(g.f(f.f(a))))));
}
};
}
public static <A, B, C, D, E, F$, G, H> F<A, H> compose(final F<G, H> l, final F<F$, G> k, final F<E, F$> j, final F<D, E> i, final F<C, D> h, final F<B, C> g, final F<A, B> f) {
return new F<A, H>() {
public H f(A a) {
return l.f(k.f(j.f(i.f(h.f(g.f(f.f(a)))))));
}
};
}
public static <A, B> Show<TreeMap<A, B>> treeMapShow(final Show<A> showA, final Show<B> showB) {
return show(new F<TreeMap<A, B>, List<Character>>() {
public List<Character> f(final TreeMap<A, B> map) {
if (map.isEmpty()) {
return list('(', ')');
}
final List.Buffer<Character> buffer = List.Buffer.empty();
Iterator<P2<A, B>> it = map.iterator();
int size = map.size();
for (int i = 0; i < size; i++) {
P2<A, B> p = it.next();
buffer.append(showA.show(p._1())).snoc('=').append(showB.show(p._2()));
if (i < size - 1) {
buffer.snoc(',');
buffer.snoc(' ');
}
}
buffer.snoc(')');
return cons('(', buffer.toList());
}
});
}
// -----------------------------------------------------------------------
// fj.P2
// -----------------------------------------------------------------------
public static <A, B, C> F<F<A, B>, F<F<A, C>, F<A, P2<B, C>>>> P2_fanout_() {
return curry(new F3<F<A, B>, F<A, C>, A, P2<B, C>>() {
public P2<B, C> f(F<A, B> f, F<A, C> g, A a) {
return P2.fanout(f, g, a);
}
});
}
// -----------------------------------------------------------------------
// fj.P3
// -----------------------------------------------------------------------
public static <A, B, C, D> F<P3<A, B, C>, D> P3_tuple(final F<A, F<B, F<C, D>>> f) {
return new F<P3<A, B, C>, D>() {
public D f(P3<A, B, C> p3) {
return f.f(p3._1()).f(p3._2()).f(p3._3());
}
};
}
}