package ktak.immutablejava;

import java.util.Comparator;

public abstract class List<T> {
    
    public abstract <R> R visit(Visitor<R,T> visitor);
    
    public interface Visitor<R,T> {
        public R visitNil();
        public R visitCons(T head, List<T> tail);
    }
    
    public static final class Nil<T> extends List<T> {

        @Override
        public <R> R visit(Visitor<R, T> visitor) {
            return visitor.visitNil();
        }
        
    }
    
    private static class Cons<T> extends List<T> {
        
        public final T head;
        public final List<T> tail;
        
        public Cons(T head, List<T> tail) {
            this.head = head;
            this.tail = tail;
        }

        @Override
        public <R> R visit(Visitor<R, T> visitor) {
            return visitor.visitCons(head, tail);
        }
        
    }
    
    public List<T> cons(T value) {
        return new Cons<T>(value, this);
    }
    
    public Long length() {
        return this.visit(new ListLength<T>());
    }
    
    public Boolean equalTo(List<T> other, Eq<T> eq) {
        return this.visit(new ListEqualTo<T>(other, eq));
    }
    
    public List<T> reverse() {
        return this.visit(new ListReverse<T>());
    }
    
    public List<T> append(List<T> end) {
        return this.visit(new ListAppend<T>(end));
    }
    
    public <U> List<U> map(Function<T,U> f) {
        return this.visit(new ListMap<T,U>(f));
    }
    
    public Boolean isEmpty() {
        return this.visit(new ListEmpty<T>());
    }
    
    public int compareTo(List<T> other, Comparator<T> cmp) {
        return this.visit(new ListCompareTo<T>(other, cmp));
    }
    
    public <U> U foldRight(U init, Function<T,Function<U,U>> f) {
        return this.visit(new ListFoldRight<T,U>(init, f));
    }
    
}

@@ -145,24 +145,152 @@
 itor);%0A    %0A
+    public abstract %3CR%3E R match(%0A            Function%3CUnit,R%3E nilCase,%0A            Function%3CTuple%3CT,List%3CT%3E%3E,R%3E consCase);%0A    %0A
     public i
@@ -309,24 +309,24 @@
 itor%3CR,T%3E %7B%0A
-
         publ
@@ -579,32 +579,244 @@
      %7D%0A        %0A
+        @Override%0A        public %3CR%3E R match(%0A                Function%3CUnit, R%3E nilCase,%0A                Function%3CTuple%3CT, List%3CT%3E%3E, R%3E consCase) %7B%0A            return nilCase.apply(Unit.unit);%0A        %7D%0A        %0A
     %7D%0A    %0A    p
@@ -1120,32 +1120,32 @@
 , T%3E visitor) %7B%0A
-
             retu
@@ -1189,32 +1189,260 @@
      %7D%0A        %0A
+        @Override%0A        public %3CR%3E R match(%0A                Function%3CUnit, R%3E nilCase,%0A                Function%3CTuple%3CT, List%3CT%3E%3E, R%3E consCase) %7B%0A            return consCase.apply(Tuple.create(head, tail));%0A        %7D%0A        %0A
     %7D%0A    %0A    p

add match method to List