diff src/main/java/fj/data/Enumerator.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/Enumerator.java	Fri Mar 20 21:04:03 2015 +0900
@@ -0,0 +1,446 @@
+package fj.data;
+
+import fj.F;
+import fj.F2;
+import static fj.Function.*;
+import static fj.data.Option.none;
+import static fj.data.Option.some;
+
+import fj.Function;
+import fj.Ord;
+
+import static fj.Ord.*;
+import fj.Ordering;
+import static fj.Ordering.*;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+/**
+ * Abstracts over a type that may have a successor and/or predecessor value. This implies ordering for that type. A user
+ * may construct an enumerator with an optimised version for <code>plus</code>, otherwise a default is implemented using
+ * the given successor/predecessor implementations.
+ * <p/>
+ * For any enumerator e, the following laws must satisfy:
+ * <ul>
+ * <li>forall a. e.successor(a).forall(\t -> e.predecessor(t).forall(\z -> z == a))</li>
+ * <li>forall a. e.predecessor(a).forall(\t -> e.successor(t).forall(\z -> z == a))</li>
+ * <li>e.max().forall(\t -> e.successor(t).isNone)</li>
+ * <li>e.min().forall(\t -> e.predecessor(t).isNone)</li>
+ * <li>forall a n. e.plus(a, 0) == Some(a)</li>
+ * <li>forall a n | n > 0. e.plus(a, n) == e.plus(a, n - 1)</li>
+ * <li>forall a n | n < 0. e.plus(a, n) == e.plus(a, n + 1)</li>
+ * </ul>
+ *
+ * @version %build.number%
+ */
+public final class Enumerator<A> {
+  private final F<A, Option<A>> successor;
+  private final F<A, Option<A>> predecessor;
+  private final Option<A> max;
+  private final Option<A> min;
+  private final Ord<A> order;
+  private final F<A, F<Long, Option<A>>> plus;
+
+  private Enumerator(final F<A, Option<A>> successor, final F<A, Option<A>> predecessor, final Option<A> max,
+                     final Option<A> min, final Ord<A> order, final F<A, F<Long, Option<A>>> plus) {
+    this.successor = successor;
+    this.predecessor = predecessor;
+    this.max = max;
+    this.min = min;
+    this.order = order;
+    this.plus = plus;
+  }
+
+  /**
+   * Returns the potential successor of a value for this enumerator in curried form.
+   *
+   * @return The potential successor of a value for this enumerator in curried form.
+   */
+  public F<A, Option<A>> successor() {
+    return successor;
+  }
+
+  /**
+   * Returns the potential successor of a value for this enumerator.
+   *
+   * @param a The value to return the successor of.
+   * @return The potential successor of a value for this enumerator.
+   */
+  public Option<A> successor(final A a) {
+    return successor.f(a);
+  }
+
+  /**
+   * Returns the potential predecessor of a value for this enumerator in curried form.
+   *
+   * @return The potential predecessor of a value for this enumerator in curried form.
+   */
+  public F<A, Option<A>> predecessor() {
+    return predecessor;
+  }
+
+  /**
+   * Returns the potential predecessor of a value for this enumerator.
+   *
+   * @param a The value to return the predecessor of.
+   * @return The potential predecessor of a value for this enumerator.
+   */
+  public Option<A> predecessor(final A a) {
+    return predecessor.f(a);
+  }
+
+  /**
+   * Returns the maximum value for this enumerator if there is one.
+   *
+   * @return The maximum value for this enumerator if there is one.
+   */
+  public Option<A> max() {
+    return max;
+  }
+
+  /**
+   * Returns the minimum value for this enumerator if there is one.
+   *
+   * @return The minimum value for this enumerator if there is one.
+   */
+  public Option<A> min() {
+    return min;
+  }
+
+  /**
+   * Returns a function that moves a value along the enumerator a given number of times.
+   *
+   * @return A function that moves a value along the enumerator a given number of times.
+   */
+  public F<A, F<Long, Option<A>>> plus() {
+    return plus;
+  }
+
+  /**
+   * Returns a function that moves a value along the enumerator a given number of times.
+   *
+   * @param a The value to begin moving along from.
+   * @return A function that moves a value along the enumerator a given number of times.
+   */
+  public F<Long, Option<A>> plus(final A a) {
+    return plus.f(a);
+  }
+
+  /**
+   * Returns a function that moves a value along the enumerator a given number of times.
+   *
+   * @param l The number of times to move along the enumerator.
+   * @return A function that moves a value along the enumerator a given number of times.
+   */
+  public F<A, Option<A>> plus(final long l) {
+    return flip(plus).f(l);
+  }
+
+  /**
+   * Moves a value along the enumerator a given number of times.
+   *
+   * @param a The value to begin moving along from.
+   * @param l The number of times to move along the enumerator.
+   * @return A potential value after having moved the given number of times.
+   */
+  public Option<A> plus(final A a, final long l) {
+    return plus.f(a).f(l);
+  }
+
+  /**
+   * Returns the ordering for the enumerator.
+   *
+   * @return The ordering for the enumerator.
+   */
+  public Ord<A> order() {
+    return order;
+  }
+
+  /**
+   * Invariant functor map over this enumerator.
+   *
+   * @param f The covariant map.
+   * @param g The contra-variant map.
+   * @return An enumerator after the given functions are applied.
+   */
+  public <B> Enumerator<B> xmap(final F<A, B> f, final F<B, A> g) {
+    final F<Option<A>, Option<B>> of = new F<Option<A>, Option<B>>() {
+      public Option<B> f(final Option<A> o) {
+        return o.map(f);
+      }
+    };
+    return enumerator(compose(compose(of, successor), g),
+                      compose(compose(of, predecessor), g),
+                      max.map(f),
+                      min.map(f),
+                      order.comap(g),
+                      compose(compose(Function.<Long, Option<A>, Option<B>>compose().f(of), plus), g));
+  }
+
+  /**
+   * Returns a stream of the values from this enumerator, starting at the given value, counting up.
+   *
+   * @param a A value at which to begin the stream.
+   * @return a stream of the values from this enumerator, starting at the given value, counting up.
+   */
+  public Stream<A> toStream(final A a) {
+    final F<A, A> id = identity();
+    return Stream.fromFunction(this, id, a);
+  }
+
+  /**
+   * Create a new enumerator with the given minimum value.
+   *
+   * @param min A minimum value.
+   * @return A new enumerator identical to this one, but with the given minimum value.
+   */
+  public Enumerator<A> setMin(final Option<A> min) {
+    return enumerator(successor, predecessor, max, min, order, plus);
+  }
+
+  /**
+   * Create a new enumerator with the given maximum value.
+   *
+   * @param max A maximum value.
+   * @return A new enumerator identical to this one, but with the given maximum value.
+   */
+  public Enumerator<A> setMax(final Option<A> max) {
+    return enumerator(successor, predecessor, max, min, order, plus);
+  }
+
+  /**
+   * Construct an enumerator.    `
+   *
+   * @param successor   The successor function.
+   * @param predecessor The predecessor function.
+   * @param max         The potential maximum value.
+   * @param min         The potential minimum value.
+   * @param order       The ordering for the type.
+   * @param plus        The function to move the enumeration a given number of times. This may be supplied for a performance
+   *                    enhancement for certain types.
+   * @return An enumerator with the given values.
+   */
+  public static <A> Enumerator<A> enumerator(final F<A, Option<A>> successor, final F<A, Option<A>> predecessor,
+                                             final Option<A> max, final Option<A> min, final Ord<A> order,
+                                             final F<A, F<Long, Option<A>>> plus) {
+    return new Enumerator<A>(successor, predecessor, max, min, order, plus);
+  }
+
+  /**
+   * Construct an enumerator. The <code>plus</code> function is derived from the <code>successor</code> and
+   * <code>predecessor</code>.
+   *
+   * @param successor   The successor function.
+   * @param predecessor The predecessor function.
+   * @param max         The potential maximum value.
+   * @param min         The potential minimum value.
+   * @param order       The ordering for the type.
+   * @return An enumerator with the given values.
+   */
+  public static <A> Enumerator<A> enumerator(final F<A, Option<A>> successor, final F<A, Option<A>> predecessor,
+                                             final Option<A> max, final Option<A> min, final Ord<A> order) {
+    return new Enumerator<A>(successor, predecessor, max, min, order, curry(new F2<A, Long, Option<A>>() {
+      public Option<A> f(final A a, final Long l) {
+        if (l == 0L)
+          return some(a);
+        else if (l < 0L) {
+          A aa = a;
+          for (long x = l; x < 0; x++) {
+            final Option<A> s = predecessor.f(aa);
+            if (s.isNone())
+              return none();
+            else
+              aa = s.some();
+          }
+          return some(aa);
+        } else {
+          A aa = a;
+          for (long x = l; x > 0; x--) {
+            final Option<A> s = successor.f(aa);
+            if (s.isNone())
+              return none();
+            else
+              aa = s.some();
+          }
+          return some(aa);
+        }
+      }
+    }));
+  }
+
+  /**
+   * An enumerator for <code>boolean</code>.
+   */
+  public static final Enumerator<Boolean> booleanEnumerator = enumerator(new F<Boolean, Option<Boolean>>() {
+    public Option<Boolean> f(final Boolean b) {
+      return b ? Option.<Boolean>none() : some(true);
+    }
+  }, new F<Boolean, Option<Boolean>>() {
+    public Option<Boolean> f(final Boolean b) {
+      return b ? some(false) : Option.<Boolean>none();
+    }
+  }, some(true), some(false), booleanOrd);
+
+  /**
+   * An enumerator for <code>byte</code>.
+   */
+  public static final Enumerator<Byte> byteEnumerator = enumerator(new F<Byte, Option<Byte>>() {
+    public Option<Byte> f(final Byte b) {
+      return b == Byte.MAX_VALUE ? Option.<Byte>none() : some((byte) (b + 1));
+    }
+  }, new F<Byte, Option<Byte>>() {
+    public Option<Byte> f(final Byte b) {
+      return b == Byte.MIN_VALUE ? Option.<Byte>none() : some((byte) (b - 1));
+    }
+  }, some(Byte.MAX_VALUE), some(Byte.MIN_VALUE), byteOrd);
+
+  /**
+   * An enumerator for <code>char</code>.
+   */
+  public static final Enumerator<Character> charEnumerator = enumerator(new F<Character, Option<Character>>() {
+    public Option<Character> f(final Character c) {
+      return c == Character.MAX_VALUE ? Option.<Character>none() : some((char) (c + 1));
+    }
+  }, new F<Character, Option<Character>>() {
+    public Option<Character> f(final Character c) {
+      return c == Character.MIN_VALUE ? Option.<Character>none() : some((char) (c - 1));
+    }
+  }, some(Character.MAX_VALUE), some(Character.MIN_VALUE), charOrd);
+
+  /**
+   * An enumerator for <code>double</code>.
+   */
+  public static final Enumerator<Double> doubleEnumerator = enumerator(new F<Double, Option<Double>>() {
+    public Option<Double> f(final Double d) {
+      return d == Double.MAX_VALUE ? Option.<Double>none() : some(d + 1D);
+    }
+  }, new F<Double, Option<Double>>() {
+    public Option<Double> f(final Double d) {
+      return d == Double.MIN_VALUE ? Option.<Double>none() : some(d - 1D);
+    }
+  }, some(Double.MAX_VALUE), some(Double.MIN_VALUE), doubleOrd);
+
+  /**
+   * An enumerator for <code>float</code>.
+   */
+  public static final Enumerator<Float> floatEnumerator = enumerator(new F<Float, Option<Float>>() {
+    public Option<Float> f(final Float f) {
+      return f == Float.MAX_VALUE ? Option.<Float>none() : some(f + 1F);
+    }
+  }, new F<Float, Option<Float>>() {
+    public Option<Float> f(final Float f) {
+      return f == Float.MIN_VALUE ? Option.<Float>none() : some(f - 1F);
+    }
+  }, some(Float.MAX_VALUE), some(Float.MIN_VALUE), floatOrd);
+
+  /**
+   * An enumerator for <code>int</code>.
+   */
+  public static final Enumerator<Integer> intEnumerator = enumerator(new F<Integer, Option<Integer>>() {
+    public Option<Integer> f(final Integer i) {
+      return i == Integer.MAX_VALUE ? Option.<Integer>none() : some(i + 1);
+    }
+  }, new F<Integer, Option<Integer>>() {
+    public Option<Integer> f(final Integer i) {
+      return i == Integer.MIN_VALUE ? Option.<Integer>none() : some(i - 1);
+    }
+  }, some(Integer.MAX_VALUE), some(Integer.MIN_VALUE), intOrd);
+
+  /**
+   * An enumerator for <code>BigInteger</code>.
+   */
+  public static final Enumerator<BigInteger> bigintEnumerator = enumerator(new F<BigInteger, Option<BigInteger>>() {
+    public Option<BigInteger> f(final BigInteger i) {
+      return some(i.add(BigInteger.ONE));
+    }
+  }, new F<BigInteger, Option<BigInteger>>() {
+    public Option<BigInteger> f(final BigInteger i) {
+      return some(i.subtract(BigInteger.ONE));
+    }
+  }, Option.<BigInteger>none(), Option.<BigInteger>none(), bigintOrd, curry(
+      new F2<BigInteger, Long, Option<BigInteger>>() {
+        public Option<BigInteger> f(final BigInteger i, final Long l) {
+          return some(i.add(BigInteger.valueOf(l)));
+        }
+      }));
+
+  /**
+   * An enumerator for <code>BigDecimal</code>.
+   */
+  public static final Enumerator<BigDecimal> bigdecimalEnumerator = enumerator(new F<BigDecimal, Option<BigDecimal>>() {
+    public Option<BigDecimal> f(final BigDecimal i) {
+      return some(i.add(BigDecimal.ONE));
+    }
+  }, new F<BigDecimal, Option<BigDecimal>>() {
+    public Option<BigDecimal> f(final BigDecimal i) {
+      return some(i.subtract(BigDecimal.ONE));
+    }
+  }, Option.<BigDecimal>none(), Option.<BigDecimal>none(), bigdecimalOrd, curry(
+      new F2<BigDecimal, Long, Option<BigDecimal>>() {
+        public Option<BigDecimal> f(final BigDecimal d, final Long l) {
+          return some(d.add(BigDecimal.valueOf(l)));
+        }
+      }));
+
+  /**
+   * An enumerator for <code>long</code>.
+   */
+  public static final Enumerator<Long> longEnumerator = enumerator(new F<Long, Option<Long>>() {
+    public Option<Long> f(final Long i) {
+      return i == Long.MAX_VALUE ? Option.<Long>none() : some(i + 1L);
+    }
+  }, new F<Long, Option<Long>>() {
+    public Option<Long> f(final Long i) {
+      return i == Long.MIN_VALUE ? Option.<Long>none() : some(i - 1L);
+    }
+  }, some(Long.MAX_VALUE), some(Long.MIN_VALUE), longOrd);
+
+  /**
+   * An enumerator for <code>short</code>.
+   */
+  public static final Enumerator<Short> shortEnumerator = enumerator(new F<Short, Option<Short>>() {
+    public Option<Short> f(final Short i) {
+      return i == Short.MAX_VALUE ? Option.<Short>none() : some((short) (i + 1));
+    }
+  }, new F<Short, Option<Short>>() {
+    public Option<Short> f(final Short i) {
+      return i == Short.MIN_VALUE ? Option.<Short>none() : some((short) (i - 1));
+    }
+  }, some(Short.MAX_VALUE), some(Short.MIN_VALUE), shortOrd);
+
+  /**
+   * An enumerator for <code>Ordering</code>.
+   */
+  public static final Enumerator<Ordering> orderingEnumerator = enumerator(new F<Ordering, Option<Ordering>>() {
+    public Option<Ordering> f(final Ordering o) {
+      return o == LT ? some(EQ) : o == EQ ? some(GT) : Option.<Ordering>none();
+    }
+  }, new F<Ordering, Option<Ordering>>() {
+    public Option<Ordering> f(final Ordering o) {
+      return o == GT ? some(EQ) : o == EQ ? some(LT) : Option.<Ordering>none();
+    }
+  }, some(GT), some(LT), orderingOrd);
+
+  /**
+   * An enumerator for <code>Natural</code>
+   */
+  public static final Enumerator<Natural> naturalEnumerator = enumerator(new F<Natural, Option<Natural>>() {
+    public Option<Natural> f(final Natural n) {
+      return Option.some(n.succ());
+    }
+  }, new F<Natural, Option<Natural>>() {
+    public Option<Natural> f(final Natural n) {
+      return n.pred();
+    }
+  }, Option.<Natural>none(), some(Natural.ZERO), naturalOrd, curry(new F2<Natural, Long, Option<Natural>>() {
+    public Option<Natural> f(final Natural n, final Long l) {
+      return some(n).apply(Natural.natural(l).map(Function.curry(new F2<Natural, Natural, Natural>() {
+        public Natural f(final Natural n1, final Natural n2) {
+          return n1.add(n2);
+        }
+      })));
+    }
+  }));
+
+}