
fj.data.hlist.HList Maven / Gradle / Ivy
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();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy