diff src/main/java/fj/data/hlist/HList.java @ 0:fe80c1edf1be

add getLoop
author tatsuki
date Fri, 20 Mar 2015 21:04:03 +0900
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/fj/data/hlist/HList.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,316 @@
+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 <A> The specific type of the list, as a subtype of HList
+ */
+public abstract class HList<A extends HList<A>> {
+
+  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 <E> HCons<E, A> extend(E e);
+
+  public abstract <E> Apply<Unit, P2<E, A>, HCons<E, A>> extender();
+
+  private static final HNil nil = new HNil();
+
+  /**
+   * Returns the empty list.
+   *
+   * @return the empty list.
+   */
+  public static HNil nil() {
+    return 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 <E, L extends HList<L>> HCons<E, L> cons(final E e, final L l) {
+    return new HCons<E, L>(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 <E> HCons<E, HNil> single(final E e) {
+    return cons(e, nil());
+  }
+
+  /**
+   * The concatenation of two heterogeneous lists.
+   *
+   * @param <A> The type of the first list.
+   * @param <B> The type of the second list.
+   * @param <C> The type of the combined list.
+   */
+  public static final class HAppend<A, B, C> {
+    private final F2<A, B, C> append;
+
+    private HAppend(final F2<A, B, C> 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 <L extends HList<L>> HAppend<HNil, L, L> append() {
+      return new HAppend<HNil, L, L>(new F2<HNil, L, L>() {
+        public L f(final HNil hNil, final L l) {
+          return 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 <X, A extends HList<A>, B, C extends HList<C>, H extends HAppend<A, B, C>>
+    HAppend<HCons<X, A>, B, HCons<X, C>> append(final H h) {
+      return new HAppend<HCons<X, A>, B, HCons<X, C>>(new F2<HCons<X, A>, B, HCons<X, C>>() {
+        public HCons<X, C> f(final HCons<X, A> c, final B l) {
+          return cons(c.head(), h.append(c.tail(), l));
+        }
+      });
+    }
+  }
+
+  /**
+   * Type-level function application operators.
+   *
+   * @param <F$> The type of the function to apply.
+   * @param <A> The domain of the function.
+   * @param <R> The function's codomain.
+   */
+  public abstract static class Apply<F$, A, R> {
+    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 <X, Y> Apply<F<X, Y>, X, Y> f() {
+      return new Apply<F<X, Y>, X, Y>() {
+        public Y apply(final F<X, Y> 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 <X> Apply<Unit, X, X> id() {
+      return new Apply<Unit, X, X>() {
+        public X apply(final Unit f, final X x) {
+          return x;
+        }
+      };
+    }
+
+    /**
+     * A function application operator for function composition.
+     *
+     * @param <X> The domain.
+     * @param <Y> The type through which to compose.
+     * @param <Z> The codomain.
+     * @return an operator that composes functions.
+     */
+    public static <X, Y, Z> Apply<Unit, P2<F<X, Y>, F<Y, Z>>, F<X, Z>> comp() {
+      return new Apply<Unit, P2<F<X, Y>, F<Y, Z>>, F<X, Z>>() {
+        public F<X, Z> apply(final Unit f, final P2<F<X, Y>, F<Y, Z>> fs) {
+          return compose(fs._2(), fs._1());
+        }
+      };
+    }
+
+    /**
+     * An operator for the construction of heterogeneous lists.
+     *
+     * @return an operator that constructs heterogeneous lists.
+     */
+    public static <E, L extends HList<L>> Apply<Unit, P2<E, L>, HCons<E, L>> cons() {
+      return new Apply<Unit, P2<E, L>, HCons<E, L>>() {
+        public HCons<E, L> apply(final Unit f, final P2<E, L> p) {
+          return HList.cons(p._1(), p._2());
+        }
+      };
+    }
+
+    /**
+     * A function application operator for concatenating heterogeneous lists.
+     *
+     * @param <A> The type of the list to which to append.
+     * @param <B> The type of the list to append.
+     * @param <C> The type of the concatenated list.
+     * @return an operator that concatenates heterogeneous lists.
+     */
+    public static <A, B, C> Apply<HAppend<A, B, C>, P2<A, B>, C> append() {
+      return new Apply<HAppend<A, B, C>, P2<A, B>, C>() {
+        public C apply(final HAppend<A, B, C> f, final P2<A, B> p) {
+          return f.append(p._1(), p._2());
+        }
+      };
+    }
+  }
+
+  /**
+   * The catamorphism over heterogeneous lists.
+   *
+   * @param <G> The type of the function with which to fold.
+   * @param <V> The type of the value to be substituted for the empty list.
+   * @param <L> The type of the heterogeneous list to be folded.
+   * @param <R> The return type of the fold.
+   */
+  public static final class HFoldr<G, V, L, R> {
+
+    private final F3<G, V, L, R> foldRight;
+
+    private HFoldr(final F3<G, V, L, R> foldRight) {
+      this.foldRight = foldRight;
+    }
+
+    /**
+     * A fold instance for the empty list.
+     *
+     * @param <G> The type of the function with which to fold.
+     * @param <V> The type of value that this fold returns.
+     * @return a fold instance for the empty list.
+     */
+    public static <G, V> HFoldr<G, V, HNil, V> hFoldr() {
+      return new HFoldr<G, V, HNil, V>(new F3<G, V, HNil, V>() {
+        public V f(final G f, final V v, final HNil hNil) {
+          return 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 <E>  The type of the head of the list.
+     * @param <G>  The type of function to apply to the head of the list and the fold of its tail.
+     * @param <V>  The type of value to substitute for the empty list.
+     * @param <L>  The type of the tail of the list.
+     * @param <R>  The type of the fold of the tail of the list.
+     * @param <RR> The return type of the fold.
+     * @param <H>  The type of the fold instance for the tail of the list.
+     * @param <PP> The type of the given function application operator.
+     * @return A fold instance for a non-empty heterogeneous list.
+     */
+    public static <E, G, V, L extends HList<L>, R, RR,
+        H extends HFoldr<G, V, L, R>,
+        PP extends Apply<G, P2<E, R>, RR>>
+    HFoldr<G, V, HCons<E, L>, RR> hFoldr(final PP p, final H h) {
+      return new HFoldr<G, V, HCons<E, L>, RR>(new F3<G, V, HCons<E, L>, RR>() {
+        public RR f(final G f, final V v, final HCons<E, L> c) {
+          return 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<E, L extends HList<L>> extends HList<HCons<E, L>> {
+    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 <X> Apply<Unit, P2<X, HCons<E, L>>, HCons<X, HCons<E, L>>> extender() {
+      return Apply.cons();
+    }
+
+    public <X> HCons<X, HCons<E, L>> extend(final X e) {
+      return cons(e, this);
+    }
+
+  }
+
+  /**
+   * The empty list
+   */
+  public static final class HNil extends HList<HNil> {
+    HNil() {
+    }
+
+    public <E> HCons<E, HNil> extend(final E e) {
+      return cons(e, this);
+    }
+
+    public <E> Apply<Unit, P2<E, HNil>, HCons<E, HNil>> extender() {
+      return Apply.cons();
+    }
+
+  }
+}