@Override
  public Parser compact(Set seen)
  {
    if (! seen.contains(this))
    {
      seen.add(this);
      l1 = l1.compact(seen);
      l2 = l2.compact(seen);
    }
    if (l1 == Empty.empty || l2 == Empty.empty)
    {
      return Empty.empty;
    }
    else if (l1 instanceof Epsilon && ((Epsilon) l1).size() == 1)
    {
      final Set trees = l1.deriveNull();
      final Object o = trees.toArray()[0];
      final Reduction r = new Reduction<Object,Object>() { @Override public Object reduce(Object t) { return new Pair(o,t); } };
      return new Reduce(l2, r);
    }
    else if (l2 instanceof Epsilon && ((Epsilon) l2).size() == 1)
    {
      final Set trees = l2.deriveNull();
      final Object o = trees.toArray()[0];
      final Reduction r = new Reduction<Object,Object>() { @Override public Object reduce(Object t) { return new Pair(t,o); } };
      return new Reduce(l1, r);
    }
    else
    {
      return this;
    }
  }