package edu.neu.ccs.demeterf.examples;
import edu.neu.ccs.demeterf.*;

/** functional list test classes. A few Map/Fold examples.*/
public class FuncTest{
    public static void main(String[] args){
        List<Integer> lst = List.from(new Integer[]{1,5,2,6,3,4,7});
        System.out.println(" String: "+lst);
        System.out.println(" Length: "+new Traversal(new Length()).traverse(lst));
        System.out.println("    Sum: "+new Traversal(new Sum()).traverse(lst));
        System.out.println("   Add1: "+new Traversal(new Add1()).traverse(lst));
        System.out.println("    I2S: "+new Traversal(new Int2Str()).traverse(lst));
    // functional lists... 
    static abstract class List<T>{
        static <S> List<S> from(S a[]){ return from(a,0); }
        static <S> List<S> from(S a[], int i){
            if(i == a.length) return new Empty<S>();
            return new Cons<S>(a[i], from(a,i+1));
        public String toString(){
            return new Traversal(new Fold<Object, String>(){
                String combine(Empty<Object> l){ return "()"; }
                String combine(Cons<Object> l, Object first, String r){
                    return "("+first+" "+r+")";
    static class Empty<T> extends List<T>{}
    static 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
    static abstract class Fold<T, R> extends ID{
        abstract R combine(Empty<T> l);
        abstract R combine(Cons<T> l, T f, R r);

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

    // A Few simple transformations
    static class Add1 extends Bc{ int combine(int i){ return i+1; } }
    public static class Int2Str extends Bc{ String combine(int i){ return "\'"+i+"\'"; } }