package edu.neu.ccs.demeterf.examples;
/** Functional Transformation Test Class.  This includes structural duplication,
 *  <code>Int2Str</code>, and a simple type unifying traversal, <code>ToString</code>.
 */

// Import the Transformation Package
import edu.neu.ccs.demeterf.*;
import edu.neu.ccs.demeterf.IDb;
import edu.neu.ccs.demeterf.IDf;

// Functional Lists in Java 
abstract class List<T>{}
class Empty<T> extends List<T>{}
class Cons<T> extends List<T>{
    T first;
    List<T> rest;
    Cons(T f, List<T> r){ first = f; rest = r; }
}

// Fold and Map Using Builders
abstract class Fold<T, R> extends IDb{
    public abstract R combine(Empty<T> l);
    public abstract R combine(Cons<T> l, T f, R r);
}
class Map<T, R> extends IDb{
    public List<R> combine(Empty<T> l){ return new Empty<R>(); }
    public List<R> combine(Cons<T> l, R f, List<R> r){ return new Cons<R>(f, r); }
}

// A Few Instances of Fold...
class Length extends Fold<Integer, Integer>{
    public Integer combine(Empty<Integer> l){ return 0; }
    public Integer combine(Cons<Integer> l, Integer f, Integer r){ return r+1; }
} 
class Sum extends Length{
    public Integer combine(Cons<Integer> l, Integer f, Integer r){ return f+r; }
} 

// A Few Functions for Transformations
class Add1 extends IDf{ public Integer apply(Integer i){ return i+1; } }
class Int2Str extends IDf{ public String apply(Integer i){ return "'"+i+"'"; } }

// ToString Builder (Builds a String)
class ToString extends Fold<Object, String>{
    public String combine(Empty<Object> l){ return "()"; }
    public String combine(Cons<Object> l, Object first, String r){ return "("+first+" "+r+")"; }
} 

// Test Class
public class FuncTest{
    private FuncTest(){}
    static void print(String s){ System.out.println(s); }  
    public static void main(String[] args){
        List<Integer> lst = fromArray(new Integer[]{1,5,2,6,3,4,7});
        Traversal str = new Traversal(new ToString()),
                  len = new Traversal(new Length()),
                  sum = new Traversal(new Sum()),
                  add = new Traversal(new Add1()),
                  i2s = new Traversal(new Int2Str());
        
        print(" String: "+str.<String>traverse(lst));
        print(" Length: "+len.<Integer>traverse(lst));
        print("    Sum: "+sum.<Integer>traverse(lst));
        print("   Add1: "+str.<String>traverse(add.<List<?>>traverse(lst)));
        print("    I2S: "+str.<String>traverse(i2s.<List<?>>traverse(lst)));
    }
    
    // Create a List from an Array
    static <S> List<S> fromArray(S a[]){ return fromArray(a,0); }
    static <S> List<S> fromArray(S a[], int i){
        if(i == a.length) return new Empty<S>();
        return new Cons<S>(a[i], fromArray(a,i+1));
    }
}