fj.data.hlist.HList Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of functionaljava Show documentation
Show all versions of functionaljava Show documentation
Functional Java is an open source library that supports closures for the Java programming language
package fj.data.hlist;
import fj.F;
import fj.F2;
import fj.F3;
import fj.P;
import fj.P2;
import fj.Unit;
import static fj.Function.compose;
/**
* Type-safe heterogeneous lists.
*
* @param The specific type of the list, as a subtype of HList
*/
public abstract class HList> {
HList() {
}
/**
* Extends (cons) this list by prepending the given element, returning a new list.
*
* @param e an element to prepend to this list.
* @return a new heterogeneous list, consisting of the given element prepended to this list.
*/
public abstract HCons extend(E e);
public abstract Apply, HCons> extender();
/**
* Returns the empty list.
*
* @return the empty list.
*/
public static HNil nil() {
return HNil.nil;
}
/**
* Returns a heterogeneous list consisting of an element and another list.
*
* @param e an element to put in a list.
* @param l the rest of the list.
* @return a heterogeneous list consisting of an element and another list.
*/
public static > HCons cons(final E e, final L l) {
return new HCons<>(e, l);
}
/**
* Returns a heterogeneous list consisting of a single element.
*
* @param e an element to put in a list
* @return a heterogeneous list consisting of a single element.
*/
public static HCons single(final E e) {
return cons(e, nil());
}
/**
* The concatenation of two heterogeneous lists.
*
* @param The type of the first list.
* @param The type of the second list.
* @param The type of the combined list.
*/
public static final class HAppend {
private final F2 append;
private HAppend(final F2 f) {
append = f;
}
/**
* Append a given heterogeneous list to another.
*
* @param a a heterogeneous list to be appended to.
* @param b a heterogeneous list to append to another.
* @return a new heterogeneous list consisting of the second argument appended to the first.
*/
public C append(final A a, final B b) {
return append.f(a, b);
}
/**
* Returns a method for concatenating lists to the empty list.
*
* @return a method for concatenating lists to the empty list.
*/
public static > HAppend append() {
return new HAppend<>((hNil, l) -> l);
}
/**
* Returns a method for appending lists to a nonempty heterogeneous list.
*
* @param h a method for appending lists to the tail of the given nonempty list.
* @return a method for appending lists to a nonempty heterogeneous list.
*/
public static , B, C extends HList, H extends HAppend>
HAppend, B, HCons> append(final H h) {
return new HAppend<>((c, l) -> cons(c.head(), h.append(c.tail(), l)));
}
}
/**
* Type-level function application operators.
*
* @param The type of the function to apply.
* @param The domain of the function.
* @param The function's codomain.
*/
public abstract static class Apply {
public abstract R apply(F$ f, A a);
/**
* Function application operator.
*
* @return an operator that applies a given function to a given argument.
*/
public static Apply, X, Y> f() {
return new Apply, X, Y>() {
public Y apply(final F f, final X x) {
return f.f(x);
}
};
}
/**
* Identity operator
*
* @return An operator that returns its second argument no matter which function is being applied.
*/
public static Apply id() {
return new Apply() {
public X apply(final Unit f, final X x) {
return x;
}
};
}
/**
* A function application operator for function composition.
*
* @param The domain.
* @param The type through which to compose.
* @param The codomain.
* @return an operator that composes functions.
*/
public static Apply, F>, F> comp() {
return new Apply, F>, F>() {
public F apply(final Unit f, final P2, F> fs) {
return compose(fs._2(), fs._1());
}
};
}
/**
* An operator for the construction of heterogeneous lists.
*
* @return an operator that constructs heterogeneous lists.
*/
public static > Apply, HCons> cons() {
return new Apply, HCons>() {
public HCons apply(final Unit f, final P2 p) {
return HList.cons(p._1(), p._2());
}
};
}
/**
* A function application operator for concatenating heterogeneous lists.
*
* @param The type of the list to which to append.
* @param The type of the list to append.
* @param The type of the concatenated list.
* @return an operator that concatenates heterogeneous lists.
*/
public static Apply, P2, C> append() {
return new Apply, P2, C>() {
public C apply(final HAppend f, final P2 p) {
return f.append(p._1(), p._2());
}
};
}
}
/**
* The catamorphism over heterogeneous lists.
*
* @param The type of the function with which to fold.
* @param The type of the value to be substituted for the empty list.
* @param The type of the heterogeneous list to be folded.
* @param The return type of the fold.
*/
public static final class HFoldr {
private final F3 foldRight;
private HFoldr(final F3 foldRight) {
this.foldRight = foldRight;
}
/**
* A fold instance for the empty list.
*
* @param The type of the function with which to fold.
* @param The type of value that this fold returns.
* @return a fold instance for the empty list.
*/
public static HFoldr hFoldr() {
return new HFoldr<>((f, v, hNil) -> v);
}
/**
* A fold instance for a non-empty heterogeneous list
*
* @param p An operator that applies a function on the head of the list and the fold of its tail.
* @param h A fold instance for the tail of the list.
* @param The type of the head of the list.
* @param The type of function to apply to the head of the list and the fold of its tail.
* @param The type of value to substitute for the empty list.
* @param The type of the tail of the list.
* @param The type of the fold of the tail of the list.
* @param The return type of the fold.
* @param The type of the fold instance for the tail of the list.
* @param The type of the given function application operator.
* @return A fold instance for a non-empty heterogeneous list.
*/
public static , R, RR,
H extends HFoldr,
PP extends Apply, RR>>
HFoldr, RR> hFoldr(final PP p, final H h) {
return new HFoldr<>((f, v, c) -> p.apply(f, P.p(c.head(), h.foldRight(f, v, c.tail()))));
}
/**
* Folds a non-empty heterogeneous list.
*
* @param f A function with which to fold.
* @param v The value to substitute for the empty list.
* @param l The heterogeneous list to be folded.
* @return a value obtained by folding the given list with the given function.
*/
public R foldRight(final G f, final V v, final L l) {
return foldRight.f(f, v, l);
}
}
/**
* The nonempty list
*/
public static final class HCons> extends HList> {
private final E e;
private final L l;
HCons(final E e, final L l) {
this.e = e;
this.l = l;
}
public E head() {
return e;
}
public L tail() {
return l;
}
public Apply>, HCons>> extender() {
return Apply.cons();
}
public HCons> extend(final X e) {
return cons(e, this);
}
}
/**
* The empty list
*/
public static final class HNil extends HList {
private static final HNil nil = new HNil();
private HNil() {
}
public HCons extend(final E e) {
return cons(e, this);
}
public Apply, HCons> extender() {
return Apply.cons();
}
}
}